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;
}
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 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.
}
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.
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"
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
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.
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 in JavaScript are mostly the same as those of C and Java. For example, arithmetic, bitwise, and assignment operations. Important differences:
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 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]
}
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'
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.
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.
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);
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:
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"
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
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;
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;
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;
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
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"
}