为什么需要IIFE创建新的范围?

use*_*772 3 javascript closures lexical-scope

不懂JS的人开始

for (var i=1; i<=5; i++) {
    setTimeout( function timer(){
        console.log( i );
    }, i*1000 );
}
Run Code Online (Sandbox Code Playgroud)

6
6
6
6
6
Run Code Online (Sandbox Code Playgroud)

但是像这样使用IIFE

for (var i=1; i<=5; i++) {
    (function(){
        var j = i;
        setTimeout( function timer(){
            console.log( j );
        }, j*1000 );
    })();
}
Run Code Online (Sandbox Code Playgroud)

1
2
3
4
5
Run Code Online (Sandbox Code Playgroud)

我的问题:为什么不

for (var i=1; i<=5; i++) {
    setTimeout( function timer(){
        var j = i;
        console.log( j );
    }, i*1000 );
}
Run Code Online (Sandbox Code Playgroud)

要么

for (var i=1; i<=5; i++) {
    function timer() {
        var j = i;
        console.log(j);
    }
    setTimeout(timer, i*1000 );
}
Run Code Online (Sandbox Code Playgroud)

像IIFE的例子一样工作?在我看来,他们俩都有一个function带有新变量的声明j,这会不会创建一个具有特定设置的新词法作用域i

Ry-*_*Ry- 5

该IIFE的重要组成部分,是它运行的时候了 ; 在i更改之前,它会读取其值并将其放入新变量中。i在其他示例中读取的函数function timer()–不会立即运行,并且它放入新变量中的值就是i更改后的值。

此外,在ES6中,您可以let i = …代替var i = …IIFE,而无需IIFE或j

for (let i = 1; i <= 5; i++) {
    setTimeout(function timer() {
        console.log(i);
    }, i * 1000);
}
Run Code Online (Sandbox Code Playgroud)

因为let具有块范围而不是函数范围,并且在for循环的初始化部分中声明的变量算在for块的一半内。

  • @Isaac:如果您从不使用`var`,跳过它可能没问题= P (3认同)