- Defining functions
- Function declarations
- Function expressions
- Calling functions
- Function scope
- Scope and the function stack
- Recursion
- Nested functions and closures
- Preservation of variables
- Multiply-nested functions
- Name conflicts
- Closures
- Using the arguments object
- Function parameters
- Default parameters
- Rest parameters
- Arrow functions
- Shorter functions
- No separate
this
- Predefined functions
Primitive parameters (such as a number) are passed to functions by value; the value is passed to the function, but if the function changes the value of the parameter, this change is not reflected globally or in the calling function.
Objcets are passed by reference: If you pass an object (i.e. a non-primitive value, such as Array or a user-defined object) as a parameter and the function changes the object's properties, that change is visible outside the function.
Functions can be created with a function expression. Function expressions can be anonymous or named:
// anonymous
var square = function(number) { return number * number; };
var x = square(4); // x gets the value 16
// named
var factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1); };
console.log(factorial(3));
Function expressions are convenient when passing a function as an argument to another function. The following example shows a map function that should receive a function as first argument and an array as second argument.
function map(f, a) {
var result = [],i; // Create a new Array
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
In the following code our function receives a function defined by a function expression and executes it for every element of the array received as a second argument.
function map(f, a) {
var result = []; // Create a new Array
var i; // Declare variable
for (i = 0; i != a.length; i++)
result[i] = f(a[i]);
return result;
}
var f = function(x) {
return x * x * x;
}
var numbers = [0, 1, 2, 5, 10];
var cube = map(f,numbers);
console.log(cube);
A method is a function that is a property of an object.
Functions must be in scope when they are called, but the function declaration can be hoisted (appear below the call in the code), as in this example:
console.log(square(5));
/* ... */
function square(n) { return n * n; }
The scope of a function is the function in which it is declared, or the entire program if it is declared at the top level. function hoisting only works with function declaration and not with function expression.
console.log(square); // square is hoisted with an initial value undefined.
console.log(square(5)); // TypeError: square is not a function
var square = function(n) {
return n * n;
}
Functions are objects and function objects have methods.
Variables defined inside a function cannot be accessed from anywhere outside the function, because the variable is defined only in the scope of the function. However, a function can access all variables and functions defined inside the scope in which it is defined. In other words, a function defined in the global scope can access all variables defined in the global scope. A function defined inside another function can also access all variables defined in its parent function and any other variable to which the parent function has access.
A function can refer to and call itself. There are three ways for a function to refer to itself:
- the function's name
- arguments.callee
- an in-scope variable that refers to the function
For example, consider the following: var foo = function bar()
. Within the function body, the following are all equivalent:
bar()
arguments.callee()
foo()
A function that calls itself is called a recursive function. In some ways, recursion is analogous to a loop. Both execute the same code multiple times, and both require a condition (to avoid an infinite loop, or rather, infinite recursion in this case). For example, the following loop:
var x = 0;
while (x < 10) { // "x < 10" is the loop condition
// do stuff
x++;
}
can be converted into a recursive function and a call to that function:
function loop(x) {
if (x >= 10) // "x >= 10" is the exit condition (equivalent to "!(x < 10)")
return;
// do stuff
loop(x + 1); // the recursive call
}
loop(0);
It is possible to convert any recursive algorithm to a non-recursive one, but often the logic is much more complex and doing so requires the use of a stack. In fact, recursion itself uses a stack: the function stack.
The stack-like behavior can be seen in the following example:
function foo(i) {
if (i < 0)
return;
console.log('begin: ' + i);
foo(i - 1);
console.log('end: ' + i);
}
foo(3);
// Output:
// begin: 3
// begin: 2
// begin: 1
// begin: 0
// end: 0
// end: 1
// end: 2
// end: 3