If it’s not fun, it’s not JavaScript.
Note: This text is a part of upcoming ebook JavaScript and Node FUNdamentals: A Collection of Essential Basics.
Expressiveness
Programming languages like BASIC, Python, C has boring machine-like nature which requires developers to write extra code that’s not directly related to the solution itself. Think about line numbers in BASIC or interfaces, classes and patterns in Java.
On the other hand JavaScript inherits the best traits of pure mathematics, LISP, C# which lead to a great deal of expressiveness (and fun!).
More about Expressive Power in this post: What does “expressive” mean when referring to programming languages?
The quintessential Hello World example in Java (remember, Java is to JavaScript is what ham to a hamster):
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World");
}
}
The same example in JavaScript:
console.log('Hello World')
or from within an HTML page:
<script>
document.write('Hello World')
</script>
JavaScript allows programmers to focus on the solution/problem rather that to jump through hoops and API docs.
Loose Typing
Automatic type casting works well most of the times. It a great feature that saves a lot of time and mental energy! There’re only a few primitives types:
- String
- Number (both integer and real)
- Boolean
- Undefined
- Null
Everything else is an object, i.e., mutable keyed collections. Read Stackoverflow on What does immutable mean?
Also, in JavaScript there are String, Number and Boolean objects which contain helpers for the primitives:
'a' === new String('a') //false
but
'a' === new String('a').toString() //true
or
'a' == new String('a') //true
By the way, ==
performs automatic type casting while ===
not.
Object Literal Notation
Object notation is super readable and compact:
var obj = {
color: "green",
type: "suv",
owner: {
...
}
}
Remember that functions are objects?
var obj = function () {
// do something
};
obj.a =1;
console.log (obj.a); // prints 1
Another very similar looking pattern (but completely different in behavior) is when we use function to construct/initialize objects:
var Obj = function (ops) {
this.name = ops.name;
}
var obj = new Obj ({name: 'puppy'});
console.log(obj);
Functions
Functions are first-class citizens, and we treat them as variables, because they are objects! Yes, functions can even have properties/attributes.
Create a Function
var f = function f () {
console.log('Hi');
return true;
}
or
function f () {
console.log('Hi');
return true;
}
Function with a property (remember functions are just object that can be invoked, i.e. initialized):
var f = function () {console.log('Boo');}
f.boo = 1;
f(); //outputs Boo
console.log(f.boo); //outputs 1
Note: the return keyword is optional. In case its omitted the function will return undefined
upon invocation.
Pass Functions as Params
var convertNum = function (num) {
return num + 10;
}
var processNum = function (num, fn) {
return fn(num);
}
processNum(10, convertNum);
Invocation vs. Expression
Function definition:
function f () {};
Invocation:
f();
Expression (because it resolve to some value which could be a number, a string, an object or a boolean):
function f() {return false;}
f();
Statement:
function f(a) {console.log(a);}
Arrays
Arrays are also objects which have some special methods inherited from Array.prototype global object. Nevertheless, JavaScript Arrays are not real arrays. Instead, they are objects with unique integer (usually 0-based) keys.
var arr = [];
var arr2 = [1, "Hi", {a:2}, function () {console.log('boo');}];
var arr3 = new Array();
var arr4 = new Array(1,"Hi", {a:2}, function () {console.log('boo');});
Prototypal Nature
There are no classes in JavaScript because objects inherit directly from other objects which is called prototypal inheritance: There are a few types of inheritance patterns in JS:
- Classical
- Pseudo-classical
- Functional
Example of the functional inheritance pattern:
var user = function (ops) {
return { firstName: ops.name || 'John'
, lastName: ops.name || 'Doe'
, email: ops.email || 'test@test.com'
, name: function() { return this.firstName + this.lastName}
}
}
var agency = function(ops) {
ops = ops || {}
var agency = user(ops)
agency.customers = ops.customers || 0
agency.isAgency = true
return agency
}
Conventions
Most of these conventions (with semi-colons being an exception) are stylistic, and highly preferencial and don’t impact the execution.
Semi-Colons
Optional semi-colons, except for two cases:
- In for loop construction:
for (var i=0; i++; i<n)
- When a new line starts with parentheses, e.g., Immediately-Invoked Function Expression (IIFE):
;(function(){...}())
camelCase
cameCase, except for class names which are CapitalCamelCase, e.g.,
var MainView = Backbone.View.extend({...})
var mainView = new MainView()
Naming
_
,$
are perfectly legitimate characters for the literals (jQuery and Underscore libraries use them a lot).
Private methods and attributes start with _ (does nothing by itself!).
Commas
Comma-first approach
var obj = { firstName: "John"
, lastName: "Smith"
, email: "johnsmith@gmail.com"
}
Indentation
Usually it’s either tab, 4 or 2 space indentation with their supporters’ camps being almost religiously split between the options.
White spaces
Usually, there is a space before and after =
, +
, {
and }
symbols. There is no space on invocation, e.g., arr.push(1);
, but there’s a space when we define an anonymous function: function () {}
.
No Modules
At least until ES6, everything is in the global scope, a.k.a. window
and included via <script>
tags. However, there are external libraries that allow for workarounds:
- CommonJS
- AMD and Require.js
Node.js uses CommonJS-like syntax and has build-in support for modules.
To hide your code from global scope, make private attributes/methods use closures and immediately-invoked function expressions (or IIFEs).
Immediately-Invoked Function Expressions (IIFEs)
(function () {
window.yourModule = {
...
};
}());
This snippet show an example of a object with private attribute and method:
(function () {
window.boo = function() {
var _a = 1;
var inc = function () {
_a++;
console.log(_a);
return _a;
};
return {
increment: inc
};
}
}());
var b = window.boo();
b.increment();
Now try this:
b.increment();
b.increment();
b.increment();
keyword “this”
Mutates/changes a lot (especially in jQuery)!
Rule of thumb is to re-assign to a locally scoped variable before attempting to use this
inside of a closure:
var app = this
$('a').click(function(e){
console.log(this) //most likely the event or the target anchor element
console.log(app) //that's what we want!
app.processData(e)
})
When in doubt: console.log!
Pitfalls
JS is the only language that programmers think they shouldn’t learn. Things like ===
vs. ==
, global scope leakage, DOM, etc. might lead to problems down the road. This is why it’s important to understand the language or use something like CoffeeScript, that take a way most of the issues.
Further Learning
If you liked this articled and would like to explore JavaScript more, take a look at this amazing free resource: Eloquent JavaScript: A Modern Introduction to Programming.
Of course for more advanced JavaScript enthusiasts and pros, there’s my book Rapid Prototyping with JS and intensive programming school HackReactor, where I teach part-time.
The correct syntax of the for loop is:
for ( initialize variable, condition, increment/decrement ){
//do something
}
like
for ( int j = 0, j < 10, j–){
//do something
}
Fixed:
(function () {
window.boo = function() {
var _a = 1;
var inc = function () {
_a++;
console.log(_a);
return _a;
};
return {
increment: inc
};
}
}());
var b = window.boo();
b.increment();
b.increment();
b.increment();
b.increment();
function convertNum = function (num) {
return num + 10
}
this throws an error
so why don’t you fix it?
No ;)
Does this code work?
(function () {
window.boo = {
var _a = 1;
var inc = function () {
_a++;
console.log(_a);};
};
return {
increment: inc
};
}());
var b = window.boo();
b.increment();