In-depth understanding of javascript closures Part 3 - IIFE

previous words

Strictly speaking, IIFE is not a closure, because it does not meet the three conditions for a function to become a closure, but in general, people think that IIFE is a closure. use.

accomplish

A function is followed by a pair of parentheses () to denote a function call.

//函数声明语句写法
function test(){};
test();

//函数表达式写法
var test = function(){};
test();

But sometimes it is necessary to call the function immediately after the function is defined. This kind of function is called an immediately executed function, which is called an immediately invoked function expression IIFE (Imdiately Invoked Function Expression)
.

[1]: The function declaration statement requires a function name. Since there is no function name, an error will be reported.

//SyntaxError: Unexpected token (
function(){}();

[2]: A pair of parentheses is added after the function declaration statement, which is just a combination of the function declaration statement and the grouping operator. Since the grouping operator cannot be empty, an error is reported.

//SyntaxError: Unexpected token )
function foo(){}();

//等价于
function foo(){};
();//SyntaxError: Unexpected token )

[3] A function declaration statement plus a pair of valuable parentheses is just a combination of a function declaration statement and a grouping operator that does not report an error.

function foo(){}(1);

//等价于
function foo(){};
(1);

So the solution is to not let function appear at the beginning of the line and let the engine understand it as an expression.

So the most useful solution is:

(function(){ /* code */ }()); 
(function(){ /* code */ })(); 

Scope: For IIFEs, looking up variables through the scope chain is a little different than through normal functions.

[with]: The IIFE in the with statement will first be searched in the with statement, and then searched upwards. In the following code, both the f() function and IIFE return 'bar' in standard browsers, but the f() function in IE10-browser returns 'abc'.

var foo = "abc";
with({
    foo:"bar"
}){
    function f(){
        console.log(foo);
    };
    (function(){
        console.log(foo);
    })();
    f();
}

[try-catch]: In the following code, both the f() function and IIFE in standard browsers return 'error', but the f() function in IE10-browser returns '10'.

try{
    var e = 10;
    throw new Error();
}catch(e){
    function f(){
        console.log(e);
    }
    (function (){
        console.log(e);
    })();
    f();
}

[Named function expression]: In the following code, the a() function returns 1 in standard browsers, while IIFE returns the a function code; but in IE8-browser, both return 1.

function a(){
    a = 1;
    console.log(a);
};
a();
(function a(){
    a = 1;
    console.log(a);
})();

Purpose: IIFE is generally used to construct private variables to avoid global space pollution.

Next, a requirement implementation is used to illustrate the purpose of IIFE more intuitively. Suppose there is a requirement, each time the function is called, a number plus 1 is returned (the initial value of the number is 0).

[1]: Global variables
Generally , we will use global variables to save the digital state.

var a = 0;
function add(){
    return ++a;
}
console.log(add());//1
console.log(add());//2

[2]: Custom attributes
However , in the above method, the variable a is actually only related to the add function, but it is declared as a global variable, which is not suitable.
It would be more appropriate to define the variable a as a custom property of the function.

复制代码
function add(){
    return ++add.count;
}
add.count = 0; //函数本身就是一个对象,所以可以通过函数名扩展对象的属性。
console.log(add());//1
console.log(add());//2

[3]: IIFE
actually does this, but there are still problems. Some codes may reset add.count unintentionally.
It is safer to use IIFE to save the counter variable as a private variable, and it can also reduce the pollution of the global space (in fact, the closure is still used here)

var add = (function(){
    var counter = 0;
    return function(){
        return ++counter; 
    }
})();
console.log(add())//1
console.log(add())//2

Precautions

Executing the following code will report an error, indicating that a is undefined at this time.

var a = function(){
    return 1;
}
(function(){
    console.log(a());//报错
})();

This is because without the semicolon, the browser interprets the above code as follows.

var a = function(){
    return 1;
}(function(){
    console.log(a());//报错
})();

If you add a semicolon, there will be no error

var a = function(){
    return 1;
};
(function(){
    console.log(a());//1
})();

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325626898&siteId=291194637