我的一个朋友和我正在讨论什么是JS中的闭包,什么不是。我们只是想确保我们理解正确。
让我们举个例子。我们有一个计数循环,并希望在控制台上延迟打印计数器变量。因此,我们使用setTimeout和闭包来捕获计数器变量的值,以确保它不会打印N倍的值。
没有闭包或接近闭包的错误解决方案是:
for(var i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
这当然会在循环后输出10倍I的值,也就是10。
所以他的尝试是:
for(var i = 0; i < 10; i++) {
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2);
}, 1000)
})();
}
按预期打印0到9。
我告诉他,他没有使用闭包来捕获I,但他坚持说他是。我通过将for循环体放在另一个setTimeout(将他的匿名函数传递给setTimeout)中,再次打印10乘以10来证明他没有使用闭包。如果我将他的函数存储在var中,并在循环之后执行它,同样打印10乘以10。所以我的论点是,他没有真正捕获i的值,使得他的版本不是一个闭包。
我的尝试是:
for(var i = 0; i < 10; i++) {
setTimeout((function(i2){
return function() {
console.log(i2);
}
})(i), 1000);
}
所以我捕获了I(在闭包中命名为i2),但现在我返回另一个函数并传递它。在我的例子中,传递给setTimeout的函数实际上捕获了i。
现在谁在使用闭包,谁没有呢?
请注意,这两个解决方案都延迟在控制台上打印0到9,因此它们解决了最初的问题,但我们想了解这两个解决方案中哪一个使用闭包来完成这一任务。
考虑以下几点。
这创建并重新创建了一个函数f,它对i关闭,但是不同的函数!:
我= 100;
F =函数(i){返回函数(){返回++i}}(0);
警报([f, f (), f (), f (), f (), f (), f (), f (), f (), f (), f ()] . join (' \ n \ n '));
f=function(i){return new function('return ++i')}(0);/*函数声明~=表达式!* /
警报([f, f (), f (), f (), f (), f (), f (), f (), f (), f (), f ()] . join (' \ n \ n '));
当下面的语句关闭a函数本身时
(自己!之后的代码段使用了一个单独的引用f)
For (var I = 0;I < 10;我+ +){
setTimeout(new Function('console.log('+i+')'), 1000);
}
或者更明确地说:
For (var I = 0;I < 10;我+ +){
console.log(f = new Function('console.log('+i+')'));
setTimeout(f, 1000);
}
NB。f的最后一个定义是打印0之前的function(){console.log(9)}。
警告!闭包的概念可以强制地偏离初级编程的本质:
for(var i = 0;i < 10;i++)(“timeout”(“log”),1000);)
x-refs。
JavaScript闭包是如何工作的?
Javascript闭包说明
一个(JS)闭包需要函数内部的函数吗
如何理解闭包在Javascript?
Javascript局部变量和全局变量混淆
让我们看看这两种方式:
(function(){
var i2 = i;
setTimeout(function(){
console.log(i2);
}, 1000)
})();
声明并立即执行一个匿名函数,该函数在自己的上下文中运行setTimeout()。i的当前值通过先复制到i2来保存;它之所以有效,是因为可以立即执行。
setTimeout((function(i2){
return function() {
console.log(i2);
}
})(i), 1000);
声明内部函数的执行上下文,其中i的当前值保存到i2;这种方法还使用立即执行来保存值。
重要的
应该提到的是,两种方法之间的运行语义是不一样的;你的内部函数被传递给setTimeout(),而他的内部函数调用setTimeout()本身。
将这两种代码包装在另一个setTimeout()中并不能证明只有第二种方法使用闭包,只是一开始就不一样。
结论
这两种方法都使用闭包,所以这取决于个人喜好;第二种方法更容易“移动”或泛化。