It is boring to explain how Javascript Functions are declared and how Javascript Functions are called recursively. But there are some things like this, let me talk about it again. Every time I see four methods of calling Javascript functions written in a book or blog, I will think of Kong Yiji: There are four writing methods for the "Taobao" word. Do you want to write it?
Despite a bunch of bugs, Javascript is still fascinating. The core of many beautiful features of Javascript is the function of first-class objects. Functions are created, assigned to variables, passed as parameters, returned values, and attributes and methods just like other common objects. As a top-level object, a function gives Javascript powerful functional programming capabilities and brings less easily controlled flexibility.
1. function declaration
A variable declaration first creates an anonymous function and assigns it to a specified variable:
var f = function () { // function body };
Generally, we do not need to worry about whether the scope of the expression on the right of the equal sign is global or within a closure, because it can only be referenced by the variable f on the left of the equal sign. We should focus on the scope of the variable f. If the reference of f to the function is damaged (f = null) and the function is not assigned to any other variable or object attribute, anonymous functions are destroyed by the garbage collection mechanism because all references are lost.
You can also use a function expression to create a function:
function f() { // function body }
Different from the variable type, this declaration method will assign a value to a built-in attribute name of the function. At the same time, assign the function value to a variable with the same name in the current scope. (The name attribute of the function, including retriable, enumerable, and writable are both false)
function f() { // function body }console.log(f.name); // "f"console.log(f); // f()
A special feature of Javascript variables is that they advance the declaration of variables, expression-based function declaration, and the definition of the entire function, therefore, you can use it before defining a function:
console.log(f.name); // "f"console.log(f); // f()function f() { // function body }
The declaration of function expressions will be promoted to the top level of the scope. Try the following code. They are not the focus of this article:
var a = 0;console.log(a); // 0 or a()?function a () {}
Crockford suggests that the first method should always be used to declare a function. He believes that the second method relaxed the requirement that the function must be declared first and then used, leading to confusion. (Crockford is a kind of "conscientious programmer" similar to the one used in Russell's mouth to compare to vitegenst' "conscientious artist". This is a tough phrase)
Function Declaration
function f() {}
It looks like
var f = function f(){};
. While
var a = function b(){};
Create a function and assign the built-in name attribute to "B". Then assign this function to variable a. You can use a () to call it externally, however, B () cannot be used. Because the function has been assigned to a, no variable B is automatically created unless you declare a variable B with var B =. Of course, the name of this function is "B" rather than "".
You can also use the Function constructor to create a Function:
var f = new Function("a,b,c","return a+b+c;");
In this way, an anonymous function is generated in the global scope and assigned to the variable f.
2. recursive call
Recursion is used to simplify many problems, which requires calling itself in a function body:
// A simple factorial function var f = function (x) {if (x = 1) {return 1 ;} else {return x * f (x-1 );}};
The great flexibility of functions in Javascript makes it difficult to use the function name in recursion. For the above variable declaration, f is a variable, so its value is easily replaced:
var fn = f;f = function () {};
A function is a value that is assigned to fn. We expect that fn (5) can be used to calculate a value. However, because the function still references the variable f, so it cannot work normally.
The functional declaration looks better, but unfortunately:
function f(x) { if (x === 1) { return 1; } else { return x * f(x - 1); }}var fn = f;f = function () {}; // may been warning by browserfn(5); // NaN
It seems that once we define a recursive function, we must be careful not to change the variable name easily.
All of the above are functional calls, and functions also have other call methods, such as calling as object methods.
We often declare objects like this:
var obj1 = { num : 5, fac : function (x) { // function body }};
Declare an anonymous function and assign it to the object property (fac ).
If we want to write a recursion here, we need to reference the attribute itself:
var obj1 = { num : 5, fac : function (x) { if (x === 1) { return 1; } else { return x * obj1.fac(x - 1); } }};
Of course, it will also encounter the same problem as the function call method:
var obj2 = {fac: obj1.fac};obj1 = {};obj2.fac(5); // Sadness
After the method is assigned to the fac attribute of obj2, you still need to reference obj1.fac internally, so... Failed.
The other method will be improved:
var obj1 = { num : 5, fac : function (x) { if (x === 1) { return 1; } else { return x * this.fac(x - 1); } }};var obj2 = {fac: obj1.fac};obj1 = {};obj2.fac(5); // ok
Use the this keyword to obtain the attributes in the context During function execution. When obj2.fac is executed, the fac attribute of obj2 is referenced in the function.
However, the function can also be called by any context modification, that is, the omnipotent call and apply:
obj3 = {};obj1.fac.call(obj3, 5); // dead again
So recursive functions cannot work normally.
We should try to solve this problem. Do you still remember the previously mentioned function declaration method?
var a = function b(){};
This declaration method is called inline function. Although no variable B is declared outside the function, B () can be used to call itself within the function.
var fn = function f(x) { // try if you write "var f = 0;" here if (x === 1) { return 1; } else { return x * f(x - 1); }};var fn2 = fn;fn = null;fn2(5); // OK
// here show the difference between "var f = function f() {}" and "function f() {}"var f = function f(x) { if (x === 1) { return 1; } else { return x * f(x - 1); }};var fn2 = f;f = null;fn2(5); // OK
var obj1 = { num : 5, fac : function f(x) { if (x === 1) { return 1; } else { return x * f(x - 1); } }};var obj2 = {fac: obj1.fac};obj1 = {};obj2.fac(5); // ok var obj3 = {};obj1.fac.call(obj3, 5); // ok
In this way, we have a name that can be used internally, without worrying about who the recursive function is assigned and how it is called.
The arguments object inside the Javascript function has a callee attribute pointing to the function itself. Therefore, you can also use arguments. callee to internally call the function:
function f(x) { if (x === 1) { return 1; } else { return x * arguments.callee(x - 1); }}
But arguments. callee is an attribute that has been prepared to be discarded. It is likely to disappear in future ECMAscript versions. arguments. callee cannot be used when "use strict" in ECMAscript 5.
The last suggestion is: If you want to declare a recursive Function, use the new Function method with caution. The Function created by the Function constructor will re-compile a Function every time it is called, recursive calling can cause performance problems-you will find that your memory is quickly exhausted.