我的一个朋友和我目前正在讨论JS中的闭包和不闭包。我们只想确保我们正确理解它。
让我们来看这个例子。我们有一个计数循环,希望延迟在控制台上打印计数器变量。因此,我们使用setTimeout和 闭包 捕获计数器变量的值,以确保其不会打印N倍于值N的值。
setTimeout
没有 闭包 或接近 闭包 的错误解决方案是:
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
当然,它将i在循环后输出10倍的值,即10。
i
所以他的尝试是:
for(var i = 0; i < 10; i++) { (function(){ var i2 = i; setTimeout(function(){ console.log(i2); }, 1000) })(); }
按预期打印0到9。
我告诉他,他并没有使用 闭包 捕获i,但他坚持认为自己是。我通过将for循环体放在另一个循环中(将他的匿名函数传递给),再次打印10次10 证明了他没有使用 闭包 。如果我将他的函数存储在a中并在循环 后 执行它,也打印10次10,则同样适用。所以我的观点是 他并没有真正 捕获 的值 ,因此他的版本 不是 闭包的。setTimeout``setTimeout``var __i
setTimeout``setTimeout``var
我的尝试是:
for(var i = 0; i < 10; i++) { setTimeout((function(i2){ return function() { console.log(i2); } })(i), 1000); }
所以我捕获了i(i2在闭包中命名),但是现在我 返回了 另一个函数并传递了它。 就我而言,传递给setTimeout的函数实际上捕获了i。
i2
现在谁在使用闭包,谁没有?
请注意,这两种解决方案在控制台上都延迟输出0到9,因此它们可以解决原始问题,但是我们想了解这两种解决方案中的哪一种 使用闭包 来完成此任务。
编者按: 在JavaScript中所有的功能都关闭在这个解释后但是,我们只对确定这些功能的子集感兴趣,这从理论上讲是很[有趣的。此后,除非另有说明,否则对闭包一词的任何引用都将指代此功能子集。
闭包的简单说明:
现在,让我们用它来找出谁使用闭包,谁不使用闭包(为便于说明,我将函数命名为):
情况1:您朋友的程序
for (var i = 0; i < 10; i++) { (function f() { var i2 = i; setTimeout(function g() { console.log(i2); }, 1000); })(); }
在以上程序中,有两个功能:f和g。让我们看看它们是否为闭包:
f
g
对于f:
console
因此,该功能f不是闭包。
对于g:
因此,该功能g是用于自由变量的封闭i2(这是用于的upvalue g) 当 它的 引用 从内setTimeout。
对您不利: 您的朋友正在使用闭包。内部函数是一个闭包。
情况2:您的程序
for (var i = 0; i < 10; i++) { setTimeout((function f(i2) { return function g() { console.log(i2); }; })(i), 1000); }
对您有好处: 您正在使用闭包。内部函数是一个闭包。
因此,您和您的朋友都在使用闭包。别吵了 我希望我清除了闭包的概念以及如何为你们两个人识别它们。
编辑: 关于为什么所有函数都关闭的简单说明(点数@Peter):
首先让我们考虑以下程序(它是control):
lexicalScope(); function lexicalScope() { var message = "This is the control. You should be able to see this message being alerted."; regularFunction(); function regularFunction() { alert(eval("message")); } }
lexicalScope
regularFunction
message
接下来让我们考虑以下程序(这是替代程序):
var closureFunction = lexicalScope(); closureFunction(); function lexicalScope() { var message = "This is the alternative. If you see this message being alerted then in means that every function in JavaScript is a closure."; return function closureFunction() { alert(eval("message")); }; }
closureFunction
我们从中得出什么呢?