If it's not fun, it's not JavaScript.
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.
Automatic type casting (mostly). 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.
var obj = {
color: "green",
type: "suv",
owner: {
...
}
}
Remember that functions are objects?
var obj = function () {
this.color: "green",
this.type: "suv",
this.owner: {
...
}
}
Functions are first-class citizens, and we treat them as variables, because they are objects! Yes, functions can even have properties/attributes.
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.
var convertNum = function (num) {
return num + 10;
}
var processNum = function (num, fn) {
return fn(num);
}
processNum(10, convertNum);
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 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');});
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 || '[email protected]'
, 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
}
Most of these conventions (with semi-colons being an exception) are stylistic, and highly preferencial and don't impact the execution.
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(){...}())
cameCase, except for class names which are CapitalCamelCase, e.g.,
var MainView = Backbone.View.extend({...})
var mainView = new MainView()
_
,$
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!).
Comma-first approach
var obj = { firstName: "John"
, lastName: "Smith"
, email: "[email protected]"
}
Usually it's either tab, 4 or 2 space indentation with their supporters' camps being almost religiously split between the options.
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 () {}
.
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).
(function () {
window.yourModule = {
...
};
}());
This snippet show an example of a object with private attribute and method:
(function () {
window.boo = {
var _a = 1;
var inc = function () {
_a++;
console.log(_a);};
};
return {
increment: inc
};
}());
var b = window.boo();
b.increment();
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!
JS is the only language that programmers think they shouldn't learn