Topics
This article is designed to provide beginners a general overview of JavaScript. It's not meant to be used as a comprehensive resource for the language. It's only meant to concisely document the features of the language. To learn JavaScript visit Codecademy. For reference and documentation of the language visit MDN. To know the best practices of the language read Crockford's blog.
Primitives and Variables
There are three primitive data types in JavaScript: boolean, number, and string. A boolean value is either true or false. It's used in conditional statements and logical operations. A number is a value that conforms to the IEEE 754-2008 double-precision floating-point format (same as Java double). It's used in arithmetic and bitwise operations. A string is finite ordered sequence of zero or more UTF-16 characters (16-bit unsigned integers).
Variables in JavaScript are weakly typed (i.e. they are not associated with a predetermined data type). Hence they may be assigned a value of any data type. The type of value assigned to a variable may change during the execution of the program, and it's not known until runtime. Hence JavaScript is dynamically typed. Variables in JavaScript are declared using the var keyword.
var n = 5;
var prime = true;
for (var i = 2; i <= Math.sqrt(n); i++) {
if (n % i === 0) {
prime = false;
break;
}
}
if (prime) alert(n + " is prime!");
else alert(n + " is not prime!");
Null and Undefined
JavaScript has two placeholders for nothing, which are null and undefined. Both of them are primitive data types. The null keyword is a value of the same data type. It's used as a placeholder for a value that does not exist. The undefined placeholder is the default value of a variable which has been declared but not defined. There exists a global variable named undefined whose value is not defined.
var god; alert(god); god = null; alert(god);
Objects and Arrays
Objects in JavaScript are hash maps, or associative arrays (i.e. simple key-value pairs). A key is a string identifier and a value is any value in JavaScript. An object can be created using an object literal, which is a comma-separated list of key-value pairs separated by a colon and enclosed in curly brackets. The properties of an object can be accessed using either the dot notation or the array index notation.
Arrays in JavaScript are not contigous memory locations. They are simply objects whose keys auto increment starting from zero. The index of an array need not be a number. It could be any valid string identifier. Arrays also have a length property which is equal to one more than the greatest key of the array which is a number. An array can be created using an array literal, which is a comma-separated list of values enclosed in square brackets. Like an object the values of an array can be accessed using either the array index notation or the dot notation.
var author = {
name: "Aadit M Shah",
dob: new Date(0xA693F0C140)
};
alert(author.name);
alert(author["dob"]);
var primes = [2, 3, 5, 7];
primes.next = 11;
alert(primes[1]);
alert(primes.length);
alert(primes["next"]);
Functions and Scopes
Functions in JavaScript are first-class objects (i.e. they can be stored in variables and they're treated as objects). A function is simply a block of code which is executed every time the function is called. It may have zero or more formal parameters and it may be called with an arbitrary number of arguments. A function can be created using a function literal which is the keyword function followed by an optional function name, a comma-separated list of zero or more formal parameter names enclosed in parentheses and the body of the function enclosed in curly brackets.
JavaScript has two main types of scopes: the global scope and the function scope. It doesn't have block scopes. Hence a variable declared inside a block is also visible outside that block in the containing function or in the global scope. Variables which are only visible inside a function are known as local variables. Variables which are visible in the global scope are known as global variables.
function count(n) {
for (var i = 0; i < n; i++)
alert(i);
alert(n);
}
count(3);
alert(n);
Globals and Hoisting
Variables declared inside a function using the var keyword are local variables which belong to that function scope. However JavaScript allows us to declare variables without using the var keyword. Such variables always belong to the global scope no matter where they are declared. This is known as a global leak. Local variables shadow global variables and variables in parent scopes with the same name. It's generally a bad idea to omit the var keyword in variable declarations.
Like variables, functions may also be declared. A function literal is known as a FunctionDeclaration when it's not used as an expression. They must have a function name. Otherwise it's known as a FunctionExpression. All declarations in JavaScript (variable declarations and function declarations) are hoisted (i.e. they are moved to the top of the global scope or the function scope depending upon where they are declared). This allows function declarations to be called before they are declared. Variables which are hoisted are always undefined because variable definitions are not hoisted.
var x = 8;
leak(10);
alert(z);
alert(x);
alert(y);
function leak(x) {
alert(y);
var y = x + 2;
z = y / 2;
}
Variadic Arguments
Functions in JavaScript may be called with any number of arguments. If the number of arguments is lesser than the number of formal parameters of a function the rest of the parameters will be undefined. If it's greater than the number of formal parameters of a function then the extra arguments may still be accessible using the free variable arguments in the function. The arguments variable has a value which is an array-like structure which holds the values of all the arguments passed onto the function. It has a property named length which holds the number of arguments the function was called with.
alert(add(2, 3, 5));
function add() {
var sum = 0;
for (var i = 0; i < arguments.length; i++)
sum += arguments[i];
return sum;
}
Constructor Functions
In classical object-oriented languages like Java objects can only be created through classes. The process of creating an object as an instance of a class is known as instantiation. JavaScript does not support classes. It's a prototypal object-oriented language. Nevertheless it does allow objects to be created via instantiation. To achieve this we use functions as constructors.
Every function has a free variable named this which normally points to the global object. If a function is a method of an object then this points to that object. If a function call is preceded by the keyword new then JavaScript creates a new object as an instance of the function and this points to the newly created object. If the function does not explicitly return a value then the newly created object is returned.
var author = new Person("Aadit M Shah", new Date(0xA693F0C140));
alert(author instanceof Person);
author.age();
function Person(name, dob) {
this.age = function () {
var age = new Date(new Date - dob);
var years = age.getUTCFullYear() - 1970;
var months = age.getUTCMonth();
var days = age.getUTCDate() - 1;
var year = years === 1 ? "year" : "years";
var month = months === 1 ? "month" : "months";
var day = days === 1 ? "day" : "days";
alert(name + " is " + years + " " + year + ", " + months + " " + month + ", " + days + " " + day + " old.");
};
}
Prototypal Inheritance
JavaScript is a prototypal object-oriented language. Inheritance in JavaScript is achieved via prototypal chains. Every function in JavaScript has a property named prototype which points that the prototype of the instances of that function. The prototype object is shared by all the instances of a function and any property defined on the prototype object is inherited by them all. The prototype object has a property named constructor which points back to constructor function.
When we create an instance of a function using the new keyword JavaScript creates a new object and sets its internal [[proto]] property to point to the prototype object of the function. This relationship identifies the object as an instance of that function. When we access a property of an object JavaScript first searches for the property on that object. If it can't find it the property on that object then it searches for the same property on the prototype of that object, and so on until a match is found or the prototypal chain ends in a null. If no match is found undefined is returned.
Prototypes are useful. They allow the public methods of a constructor to be defined once and be shared amongst all the instances of the constructor. Any modification to the prototype object affects all the instances of the constructor. However to achieve inheritance the prototype property of the derived constructor must point to an instance of the base constructor. This creates a prototypal chain. The instance of the derived constructor inherits all the properties of the instance of the base constructor and the prototype object of the base constructor. Since the instance of the base constructor doesn't have a property named constructor which points back to the derived constructor we manually add it.
function Animal(species) {
this.species = species;
}
Dog.prototype = new Animal("Dog");
Dog.prototype.constructor = Dog;
function Dog(breed) {
this.breed = breed;
}
Dalmatian.prototype = new Dog("Dalmatian");
Dalmatian.prototype.constructor = Dalmatian;
Dalmatian.prototype.collar = function () {
alert(this.name + " the " + this.breed);
};
function Dalmatian(name) {
this.name = name;
}
var lucky = new Dalmatian("Lucky");
alert(lucky instanceof Dalmatian);
alert(lucky instanceof Dog);
alert(lucky instanceof Animal);
lucky.collar();
Closures and Higher-Order Functions
JavaScript has lexical scoping which means that non-local variables accessed from within a function are resolved to variables present in the parents' scope of that function when it was defined. This is in contrast to dynamic scoping in which non-local variables accessed from within a function are resolved to variables present in the calling scope of that function when it is called. Lexical scoping along with first-class functions allow closures to be implemented in JavaScript.
Scoping rules state that a variable can only be accessed from within its own scope or its children scopes. However closures allow indirect access to variables outside the scope they live in. A closure is a function which is defined in the lexical scope of a referencing environment. Thus it has access to all the variables declared within the context of this referencing environment. First-class functions can be passed as arguments to other functions, returned from other functions, and assigned to variables. A function becomes a closure when it's moved out of its referencing environment. When this happens the function "closes over" all the non-local variables accessed from within the function. These variables are known as upvalues and can then be accessed from outside their own scopes.
A higher-order function is simply a function which does at least take one or more functions as an argument or returns a function. Higher-order functions are usually passed closures as arguments or return closures themselves. All functional programming languages have higher-order functions. Closures and higher-order functions are powerful features which allow functions to maintain an internal state.
var tick = counter();
alert(tick());
alert(tick());
alert(tick());
function counter() {
var count = 0;
return function () {
return ++count;
};
}