In JavaScript, a function is an instance of Function so you can assign it to a variable. For example:
js> function max(num1, num2) {
> return num1 > num2 ? num1 : num2;
> }
js> var maximum = max;
js> max(10, 20);
20
js> maximum(10, 20);
20
js>
> return num1 > num2 ? num1 : num2;
> }
js> var maximum = max;
js> max(10, 20);
20
js> maximum(10, 20);
20
js>
Take note of it, there's no () operator after the variable max while assigning it to maximum. This means the object refereed by max will be assigned to maximum. If there's a () after a variable, it means you want to call a function. Assign a function to a variable? If you feel this weird in the beginning, the following code may not look so:
js> var max = function(num1, num2) {
> return num1 > num2 ? num1 : num2;
> };
js> var maximum = max;
js> max(1, 2);
2
js> maximum(1, 2);
2
js>
> return num1 > num2 ? num1 : num2;
> };
js> var maximum = max;
js> max(1, 2);
2
js> maximum(1, 2);
2
js>
In the above example, a function literal is used to create a function. Function literals are like number literals, array literals and object literals. They are respectively used to create functions, numbers, arrays and objects.
var number = 10;A function literal creates an instance of Function. In JavaScript, no matter it's a function declaration or a function literal, both create an instance of Function. In fact, you can use the Function constructor to create a function directly.
var obj = { x : 10 };
var array = [1, 2, 3];
var func = function() {
// do something...
};
js> var max = new Function('num1', 'num2', 'return num1 > num2 ? num1 : num2');
js> max(5, 6);
6
js>
js> max(5, 6);
6
js>
Actually, JavaScript developers rarely use the Function constructor to create a function. The above example just shows that a function is really an instance of Function.
Now that a function is an object, it can be arbitrarily assigned to other variables. It can also be passed as an argument to other functions. That is, it can be a callback function to other functions. For example:
js> var printIt = function(element) {
> print(element);
> };
js> [1, 2, 3].forEach(printIt);
1
2
3
js> var comparator = function(num1, num2) {
> return num1 - num2;
> };
js> [5, 1, 7, 3, 2].sort(comparator);
1,2,3,5,7
js>
> print(element);
> };
js> [1, 2, 3].forEach(printIt);
1
2
3
js> var comparator = function(num1, num2) {
> return num1 - num2;
> };
js> [5, 1, 7, 3, 2].sort(comparator);
1,2,3,5,7
js>
Take an Array instance for example. The forEach method iterates each array element to let you do something. You pass a function to forEach. Each array element will be passed in turns as an argument to the callback function. The sort method can sort array elements but has to know the order of any two elements. The function passed to sort should return a negative integer, zero, or a positive integer as the first argument is less than, equal to, or greater than the second.
It's a common application to pass a function to a function in JavaScript. Actually, you can do as follows if you don't need a function name:
js> [1, 2, 3].forEach(function(element) {
> print(element);
> });
1
2
3
js> [5, 1, 7, 3, 2].sort(function(num1, num2) {
> return num1 - num2;
> });
1,2,3,5,7
js>
> print(element);
> });
1
2
3
js> [5, 1, 7, 3, 2].sort(function(num1, num2) {
> return num1 - num2;
> });
1,2,3,5,7
js>
You can also return a function from a function. The returned function usually creates a closure to bind some resource. I'll explain this afterword.
Function instances created by function literals are often anonymous functions. You can execute a function even if it has no name.
js> (function() {
> print('anonymous function...');
> })();
anonymous function...
js>
> print('anonymous function...');
> })();
anonymous function...
js>
In fact, function literals can have a name. For example:
js> var maximum = function max(num1, num2) {
> return num1 > num2 ? num1 : num2;
> };
js> maximum(10, 20);
20
js> max(10, 20);
js: "<stdin>", line 6: uncaught JavaScript runtime exception: ReferenceError: "max" is not defined.
at <stdin>:6
js>
> return num1 > num2 ? num1 : num2;
> };
js> maximum(10, 20);
20
js> max(10, 20);
js: "<stdin>", line 6: uncaught JavaScript runtime exception: ReferenceError: "max" is not defined.
at <stdin>:6
js>
It seems that max defined in the function literal is useless. Actually, the name of a function literal is suitable for a recursive context.
js> var gcd = function g(num1, num2) {
> return num2 != 0 ? g(num2, num1 % num2) : num1;
> };
js> gcd(10, 5);
5
js>
> return num2 != 0 ? g(num2, num1 % num2) : num1;
> };
js> gcd(10, 5);
5
js>
If an anonymous function wants to refer itself, it can use the callee property of arguments. For example:
js> var gcd = function(num1, num2) {
> return num2 != 0 ? arguments.callee(num2, num1 % num2) : num1;
> };
js> gcd(20, 10);
10
js>
> return num2 != 0 ? arguments.callee(num2, num1 % num2) : num1;
> };
js> gcd(20, 10);
10
js>
Since a function is an object, it can own properties. For example, a function has a length property which represents the number of parameters:
js> var gcd = function g(num1, num2) {
> return num2 != 0 ? g(num2, num1 % num2) : num1;
> };
js> gcd.length;
2
js>
> return num2 != 0 ? g(num2, num1 % num2) : num1;
> };
js> gcd.length;
2
js>
A function can have methods, which will talk afterword. You can also add properties or methods on a function, like a plain object.
Function declarations and function literals are almost the same but there are still some subtle differences. For example, if you write a f.js file as follows:
- f.js
func();
function func() {
print('func');
}
Load it into Rhino interpreter. It will execute without error.
> java org.mozilla.javascript.tools.shell.Main f.js
func
func
But if your f.js file is as follows:
- f.js
func();
var func = function() {
print('func');
};
You will get the error message:
> java org.mozilla.javascript.tools.shell.Main f.js
js: uncaught JavaScript runtime exception: TypeError: func is not a function, it is undefined.
js: uncaught JavaScript runtime exception: TypeError: func is not a function, it is undefined.
The error message tells you that func is undefined. The reason is, when an interpreter loads a js file, it first processes all declarations, including all variable and function declarations and then run the program. It's like that JavaScript hoists all declarations. You can image that all var and function declarations will be moved to the top of the enclosing scope. In the first f.js file, func is created by a function declaration so gets hoisted before the execution of the program starts.
In the second f.js, the only one declaration is the variable func. After the interpreter hoists the variable func, it starts to execute the program. The variable func is available in the scope but has not yet been specified any value. It's undefined so the interpreter cannot finish the execution of the program.
What deserves to be mentioned is function declarations and function literals both don't need to re-interpret the code when creating a function instance. But if you use the Function constructor to create a function, it's necessary to re-interpret the string arguments every time.
var max = new Function('num1', 'num2', 'return num1 > num2 ? num1 : num2');