JavaScript language constructs

Variables

var x; declares a new variable x. Variables are scoped to the nearest enclosing function, not the enclosing block. For example, this is valid:

function (x) {
	if (x > 0) {
		var y = 3;
	} else {
		var y = 7;
	}
	return y;
}

Functions

In JavaScript, functions are objects that encapsulate executable code. This section describes the basics of functions; the section on objects includes additional details.

Named functions

Named functions look similar to C or Java functions, but without type annotations (upcoming JS versions do include optional type annotations), and with the addition of the function keyword:

function f(...) {
	...
}

function addPair(x, y) {
	return x + y;
}

Function bodies consist of zero or more statements, separated by semicolons or newlines (JavaScript parsers use a heuristic to insert missing semicolons at newlines—this is usually more trouble than it's worth). Return statements are optional.

function doStuff(x, y) {
	var sum = x + y;
	alert(sum);
	// retun x + y; // This line is commented out.
}

Nested functions

Function definitions may appear inside of other functions. In that case, they are (lexically) locally scoped.

function outer(x) {
	return inner(x, x);

	function inner (y, z) {
		return y * z;
	}
}

Notice that the function definition may appear before or after its use.

Anonymous functions

Same syntax, but without a name.
function (...) {
	...
}

function (x, y) {
	return x + y;
}

An anonymous function is an expression which can be used as a value. The name of a named function can also be used as a value. Assigning an anonymous function to a variable isn't quite the same as a function declaration—this wouldn't work correctly:

function outer(x) {
	return inner(x, x);

	var inner = function (y, z) {
		return y * z;
	};
}

The solution would be to assign to inner before its use.

Anonymous functions can be assigned local names to allow recursion, without introducing the function's name into the surrounding namespace. To do so, simply use a named function as an expression rather than a statement.

var f = function myfun(x, y) {
	if (x > 0) {
		return myfun(x-1, y+1);
	} else {
		return y;
	}
};

   typeof f     == "function"
&& typeof myfun == "undefined"

Closures

Nested functions capture variables in their lexical scope, creating a closure. The variables referenced by the closure are mutable.

function makeFn() {
	var counter = 0;
	return function () {
		counter++;
		return counter;
	}
}

var f = makeFn();
var g = makeFn();

f(); // => 1
f(); // => 2
g(); // => 1
f(); // => 3
g(); // => 2

The arguments variable

Sometimes it's useful to write functions that accept a variable number of arguments. In C, this is done via the stdarg stack-inspection mechanism. In Scheme, this is done by binding a variable to the cdr position of the argument list. In Javascript, the list of arguments to a function is bound to the arguments variable.

function concat() {
	var str = '';
	for (i = 0; i < arguments.length; i++) {
		if (str != '') {
			str += ' ';
		}
		str += arguments[i];
	}
	return str;
}
var s = concat('welcome', 'to', 'javascript'); // s = 'welcome to javascript'

This is particularly useful when writing higher order functions that need to wrap the behavior of other functions.

Conditionals

Much like C or Java conditionals. Deviations from C are highlighted in bold.

if (...) {
	...
}
if (...) {
	...
} else {
	...
}

Note that if and other conditionals consider false, null and undefined as equivalent. For example, the following expression returns 3:

if (null) {
	return 8;
} else {
	return 3;
}

x = a ? b : c;

switch (...) {
case 1:
	...
	break;
case 'some string':
	...
	break;
default:
	...
}

for (var i = 1; i < 10; i++) {
	...
}
for (var fieldName in someObject) {
	...
}

while (...) {
	...
}
do {
	...
} while (...);

var x = 1;
var someObject = { z: 2 };
with (someObject) {
	var y = x + z;
}
// Equivalent to:
var x = 1;
var someObject = { z: 2 };
var y = x + someObject.z;

Other operators

Other operators in JavaScript are mostly the same as those of C and Java. For example, arithmetic, bitwise, and assignment operations. Important differences:

String concatenation

Strings can be surrounded by single or double quotes; characters are not distinguished from strings.

"this is a string"
'so is this'

+ is used for string concatenation, as well as arithmetic:

var hw = 'Hello ' + "World";
0 + 'abc' // => '0abc'
1 + 2     // => 3

Array literals

Array literals are defined using brackets, not braces. Arrays may include holes, which default to undefined. Arrays are simply objects with fields named 0, 1, 2, etc.

var a = [11,'z',,3,,,'abc',9];
a[0] // => 11
a[1] // => 'z'
a[2] // => undefined

Arrays are objects; they include a length field, which is useful for iteration. For example:

for (var i = 0; i < a.length; i++) {
	// do something with a[i]
}

typeof

The typeof operator allows you to dynamically determine the type of a value. As in Java, values in JavaScript are generally objects or primitives.

   typeof 'hello'         == 'string'
&& typeof 3               == 'number'
&& typeof { }             == 'object'
&& typeof function () { } == 'function'
&& typeof null            == 'object'
&& typeof undefined       == 'undefined'
&& typeof true            == 'boolean'

Objects

Object literals

A JavaScript object is fundamentally a key-value assocation. JavaScript is dynamically typed, and does not use classes. Object literals are denoted as follows.

var obj = { field1: expr1, field2: expr2, ... };

Object literals cannot be used directly in contexts where they may be confused with code blocks. In those cases, surround an object literal in parentheses.

Accessing fields

An object field may be accessed via either dot-notation (similar to C structures) or bracket-notation (similar to C arrays). Strings are used as indices into the fields of an object. Numbers may be used as indices as well, but they will be coerced to decimal strings.

obj.field1
obj['field2']
obj[3] // same as obj['3']

Note that when using dot-notation, you can only use field names that are proper identifiers; but when using bracket-notation, field names may be arbitrary strings.

Methods

A method in JavaScript is simply a function stored in an object field. Methods are called using dot-notation. An object's methods can also be assigned, removed, or updated dynamically, just like any other object field.

obj = { };
obj.y = 1;
obj.m = function (x) { return 2*x + this.y; }
var seven = obj.m(3);

The this variable

Within a method, the associated object is dynamically bound to the this variable. Because methods are simply functions stored as object fields, the value of this depends on the context in which a function/method is called. The three different cases are:

  1. plain functions
  2. functions used as methods
  3. functions used as constructors

Function not used as a method: this is bound to the global scope object. In a browser, the global scope is stored in the window object.

function f() {
	alert(this == window);
}
f(); // displays "true"

When a function is stored as a field of an object, it is treated as a method. When the method is invoke, the this variable will point to the object.

var obj = {
	m: function () { alert(this.x); },
	x: "hello"
};
obj.m(); // displays "hello"

However, if the method is stored to a separate variable, it is treated as a standard function again: this points to the global scope (the window object).

var m = obj.m;
window.x = "goodbye";
m(); // displays "goodbye"

The call and apply methods

Now say you have an object, and a function you want to use as a method of that object. One way to do so is to store the function in a field of the object. However, if you don't want to modify the object (or if you want to hide the method from other code that has access to the object), what do you do?

In JavaScript, functions are themselves objects. Function objects have methods call() and apply() that allow you to explicitly specify the value of this to use.

function g(y, z) {
	return this.x + y + z;
}
var obj = { x: 3 };

In order to invoke obj.g(), we'd need to update obj.

// obj.g = g;
// var a = obj.g(4, 5); // a = 12

But if we don't want to modify obj, we can use g.call(),

var b = g.call(obj, 4, 5); // b = 12

Or we can use g.apply(), especially if the number of arguments can vary.

var args = [4, 5];
var c = g.apply(obj, args); // b = 12

Constructors

In JavaScript, constructors are simply functions. To use a function as a constructor, it is called using the "new" operator. Doing so binds a fresh object to "this". The new expression automatically returns the newly-allocated object, after allowing the constructor to modify it as desired. By convention, constructors are named to describe the kind of object they initialize.

function MyObject(name) {
	this.name    = name;
	this.counter = 0;
}
var mo = new MyObject("bob");
// result:
   mo.name    == "bob"
&& mo.counter == 0;

In particular, object literal expressions implicitly call the Object constructor—i.e., the following two code sequences are equivalent.

// object literal
var obj = { x: 7 };

// or equivalently, call the Object constructor
var obj = new Object();
obj.x = 7;

Prototypes

JavaScript doesn't provide classes for structuring object-oriented programs (classes are proposed for a future version of the language). Instead, each object has an associated prototype object which specifies the default values of fields not stored directly in the object. The prototype is set when an object is constructed.

var p = { x: 0, y: 0 };
function Point() { }
Point.prototype = p;

var obj = new Point();
// result: obj inherits fields from p.
   obj.x == 0
&& obj.y == 0;

If you set a field in an object, that will override the value stored in the prototype; however, it will not modify the prototype object itself.

obj.x = 3;
// result: p.x unchanged
p.x == 0;

Changing fields of the prototype object directly will affect objects that reference that prototype.

p.x = 5;
p.y = 6;
p.z = 7;
// result:
   obj.x == 3 // Because obj.x was already set to a custom value
&& obj.y == 6
&& obj.z == 7;

A common application of prototypes in JavaScript is to encapsulate a collection of methods shared by a class of objects. The prototype mechanism is provided as an alternative to classes in other object-oriented programming languages.

function Point() { }
function PointAt(x, y) {
	this.x = x;
	this.y = y;
}
// Two different constructors, one common prototype.
PointAt.prototype =
Point.prototype = {
	x: 0,
	y: 0,
	add: function (pt) {
		this.x += pt.x;
		this.y += pt.y;
	}
};

var pt = new PointAt(2, 3);
pt.add(pt);
// result:
   pt.x == 4
&& pt.y == 6;

instanceof and .constructor

The instanceof method allows you to check whether a given object has the same prototype as a given constructor's .prototype field.

   obj   instanceof Point  == true
&& obj   instanceof Object == true
&& ({ }) instanceof Point  == false;

function AnotherConstructor() { }

obj instanceof AnotherConstructor == false;

AnotherConstructor.prototype = Point.prototype;

obj instanceof AnotherConstructor == true;

Every object has a hidden .constructor field which is supposed to point to the constructor function used to define the object. However, at least in Firefox, this only works correctly if the constructor's .prototype field was not reassigned before the object was constructed.

function f() {
}

var a = new f();
a.constructor == f;

f.prototype = { }

var b = new f();
   a.constructor == f
&& b.constructor != f;

Undefined, Null, and Comparison

JavaScript offers two comparison operators: == (double-equals: equivalent) and === (triple-equals: identical).

A declared variable initially has value undefined, which is different from the value null. However, == treats the two as equivalent:

undefined ==  null    true
undefined === null    false

Some other values are also considered as equivalent by ==, for example:

'' ==  0              true
'' === 0              false

But objects are always considered as distinct, even if they have the same fields:

({a:1}) == ({b:2})    false
({ })   == ({ })      false

Exceptions

Any object can be thrown as an exception. As in Java (and unlike the Common Lisp condition system), JavaScript exceptions are non-restartable.

throw obj;
throw { };

Java-style try/catch/finally is supported.

try {
	...
} catch (e) {
	...
}
try {
	...
} finally {
	...
}
try {
	...
} catch (e) {
	...
} finally {
	...
}

Example:

try {
	throw { name: "something" };
} catch (e) {
	alert(e.name); // => displays "something"
}