2017-02-26 68 views
1

我只是想了解Javascript中的闭包。我在三个例子中遇到了。
Expample 1:理解闭包,为每个迭代创建不同的范围

for (var i = 0; i <= 10; i++) { 
 
    setTimeout(function() { 
 
    console.log("i :" + i) 
 
    }, i * 1000); 
 
}

,并如预期的那样输出它打印的“i:11”到控制台11倍,因为对整个循环只创建一个范围是全球范围内要在每次迭代中使用不同的范围,我使用了IIFE(立即调用函数表达式),请参阅下面的代码片段。
例如:于:2-

for (var i = 0; i <= 10; i++) { 
 
    (function(i) { 
 
    setTimeout(function() { 
 
     console.log("i : " + i) 
 
    }, i * 1000) 
 
    })(i); 
 
}

它从 “0 I” 打印 “我:10” 作为预期的,因为是针对每次迭代创建不同范围。
我无法理解下面的代码段中究竟发生了什么。
例如:3

for (let i = 0; i <= 10; i++) { 
 
    setTimeout(function() { 
 
    console.log("i :" + i) 
 
    }, i * 1000); 
 
}

它输出从 “我:0” 到 “I:10”。
1.我不能理解为什么输出不像第一个例子那样相同,即打印“1:11”11次?
2。如果我使用块范围,是否为每次迭代创建了不同的作用域?
3。如果创建的范围不同,那么它与示例1有什么不同?

回答

1

这是因为let与块范围(var没有)操作。这意味着它就像在构成for语句的代码块中声明局部变量。

例如,你可以这样做:

if (blockCount === 3) { 
    let x = 1; 
    // do something with x 
} else { 
    let x = 2: 
    // do something with x 
} 

console.log(x); // undefined since no longer in scope 

书面这将工作。如果您尝试在if语句之外访问x,则它将不确定。

有关更多信息,请参阅this link

0

在第一个示例中,您调用setTimeout(),该值在特定时间后打印变量i。当setTimeout()回调触发时,循环结束并且i拥有最后的迭代值(11)。所有回调都会打印该变量。

在第二个示例中,您使用立即调用的函数表达式(IIFE)。这是一个函数,定义为立即调用,并将参数i传递给它。 当你传递一个参数给一个函数时,它就像是一个新的局部变量被声明。例如:

var foo = 5; 
 

 
function myLog(foo) { 
 
    console.log(foo); 
 
} 
 

 
myLog("not 5"); // logs "not 5" instead of 5

这意味着论点立即调用函数的i是从循环使用的i不同,但具有相同的价值,因为你在当前传递循环迭代。
通过这种方法,您可以创建12个不同的i变量。一为循环,11人的IIFEs,其使用的内部setTimeout()回调。

在第三个例子中,会发生类似的事情。 let声明一个块作用域局部变量。循环运行时,就像创建了11个不同的变量,并且每个回调都引用了在其本地范围内创建的变量。这更详细地解释here