Prerequisite: 2 JavaScript Fundamentals
Douglas Crockford, A Survey of the JavaScript Programming Language — this time read the section “Functions”, down to and including the subsubsection “Function constructor.”
We need functions to organize our code into meaningful procedural units.
Functions are defined with the keyword function:
function f (a, b) { body }
Here, the function’s name is f, its parameters are a and b, and its body is body, which is, in general, a sequence of statements. Of course, there can also be more or less than two parameters.
Here’s a function which produces some console log output:
function hb (name) {
console.log("Happy birthday");
console.log(name);
}
A function uses the return statement to return a value. Here’s a function which performs a numerical calculation and returns the result:
function calc (a, b) {
return 2.1 * a + 3.4 * b;
}
Functions can be nested; that is, we can have functions inside of functions:
function f (a, b) {
var c = a + 2;
var d = b + 3;
function g (x) { return 2 * x + 12};
return g(c) - g(d);
}
What happens if we call f(2, 5)?
Inside of f, a is 2, and b is 5. Therefore,
return statement gives us g(c) − g(d) = 20 − 28 = −28.The local variables c and d and the function g are hidden inside of the function f. We refer to this hiding as a closure: they are closed away, sealed off, from the rest of the world. This is a very powerful mechanism for hiding information, similar to Java’s private fields and methods.
Note, though, that the variables must be declared with var for this to happen. Without var, they would be global variables, accessible to the rest of the program.
The parameter of a function can itself be a function. Here’s an example:
function greeting(name, title) { return "Hello, " + title(name); }
function en_ma_title(name) { return "Sir " + name; } // English male title
function es_fe_title(name) { return "Señorita " + name; } // Spanish female title
The second parameter of the function greeting, namely title, is expected to be a function, which is applied to its first parameter, name.
What happens if we call greeting("George", en_ma_title)? We evaluate the body of greeting with name = "George" and title = en_ma_title:
greeting("George", en_ma_title) = "Hello, " + title(name) = "Hello, " + en_ma_title("George")en_ma_title("George") = "Sir " + "George" = "Sir George"greeting("George", en_ma_title) = "Hello, " + "Sir George" = "Hello, Sir George"What happens if we call greeting("Rojas", es_fe_title)?
The value returned by a function can also be a function. Here’s an example:
function adder(k) {
function adderk (x) { return x + k; };
return adderk;
}
What is the value of adder(10)? It is a function which adds 10 to its argument: namely, the inner function
function adderk (x) { return x + k; };
where k = 10, which is equivalent to
function adderk (x) { return x + 10; };
Hence, adder(10)(5) = 15.1
We could store the value of adder(10) in a variable and use the variable later:
var add10 = adder(10);
...
console.log(add10(5));
It might startle you, but it is well worth pointing out that the parameter k is a local variable in a closure, and that its value is remembered by the function stored in the variable add10 for as long as that function exists. But this particular k (with the value 10) is accessible from nowhere else!
The keyword function can be used with or without a function name. If we use a name, we are, of course, using the word function in a statement to define a named function.
If we use it without a function name, we are using the word function in an expression to to create a (so far) anonymous function, that is, a function without a name:
function (a, b) { body}
In fact, if we use function in a statement, like this,
function f (a, b) { body }
we are really creating a variable, f, that has a function as its value. It is exactly equivalent to
var f = function (a, b) { body };
The value of a function expression is simply a value which happens to be a function, because we used a function expression, just as the value of a numerical expression is a value which happens to be a number, because we used a numerical expression.
Storing a function value in a variable gives the function a name, i.e., the name of the variable, even if it did not have a name originally. You could store the same function in two different variables, and then it would have two names. The name is not part of the function: it is just a way to refer to the function.
But functions can be very useful even without names. For example, we can use an anonymous function to simplify the adder function shown above:
function adder(k) {
return function (x) { return x + k; };
}
Functions in JavaScript are, in fact, first-class values,2 meaning that they can be used in three ways, just like any other kind of value:
adder(10)(5) into parts. The first part is adder(10); its value is a function with one argument, which adds 10 to its argument and returns the result. This function is then applied to 5, yielding 15.
Explicit parentheses here emphasize the order of evaluation: (adder(10))(5)
Also called “first-class objects,” but “objects” here just means “values.” That can be confusing because functions are not objects, in the object-oriented sense, in JavaScript.↩