And*_*lly 11 javascript closures
我正在尝试学习Javascript闭包.我无法理解当你在循环中创建几个闭包时,所有闭包只保存变量的最后一个状态.有了这个例子
var links = document.getElementsByTagName('a');
for (var x=0; x<links.length; x++) attachListener();
function attachListener() {
links[x].addEventListener('click', function(){
console.log(x);
}, false);
};
Run Code Online (Sandbox Code Playgroud)
当我在我的文档中有三个链接时,点击任何链接显示"3",我想因为在最后一次循环运行后x增加到3.我在这篇优秀的介绍中读到,如果你多次运行外部函数,每次都会创建一个新的闭包.那么为什么每次调用外部函数时每个闭包都不会为x保存不同的值?
当您将x作为参数传递给外部函数时,它可以按预期工作.
var links = document.getElementsByTagName('a');
for (x=0; x<links.length; x++) attachListener(x);
function attachListener(z) {
links[z].addEventListener('click', function(){
console.log(z);
}, false);
};
Run Code Online (Sandbox Code Playgroud)
现在,当您单击第一个链接时,您将获得0,而在第二个链接上则为1.
任何人都可以解释为什么会有这种差异?
干杯
Mat*_*ard 12
闭包不会在创建变量时捕获变量的值,而是变量本身.由多个闭包关闭的变量是共享的.这是有意的,它是在JavaScript中进行封装的好方法,例如:
var makeMutablePoint = function(x, y) {
return {
position: function() {
return [x, y];
},
add: function(dx, dy) {
x = x + dx;
y = y + dy;
}
};
};
Run Code Online (Sandbox Code Playgroud)
这也是闭包在大多数其他语言中工作的方式(这是Python有时被称为没有适当的闭包的主要原因).
但是有一个方面是特定于JavaScript的,有时可能会让你失望(在这种情况下实际上似乎已经这样做了):变量总是在JavaScript中具有函数范围.例如,在您的第一个代码片段中,只有一个x变量,而有人可能期望将范围x限制为循环体(x每次迭代都有一个新变量).这是一种语言的怪癖,将来可能会通过引入let更细粒度的范围规则的关键字来改进.
我过去对这种同样的行为感到有点恼火。对我来说,这似乎是闭包实现中的一个错误。闭包应该包含“创建闭包时函数的词法环境(例如,可用变量及其值的集合) ”的快照(来源:维基百科;重点是我的)。显然,这并不完全是本例中发生的情况。
但很容易推断出幕后发生的事情。在您的第一个示例中,只有一个变量 实例x,并且当创建闭包时,JavaScript 运行时会在其中存储对创建闭包时x的当前值的引用,而不是存储当前值的副本。x因此,当循环递增时x,闭包中的“副本”似乎也会递增。
在第二种情况下,您将x其作为参数传递给函数,该函数x在传递给attachListener()函数时将 的当前值复制到新变量中。该副本的值永远不会更新(即,它与 解耦x,并且您不会在 内部修改它attachListener()),因此闭包按预期工作,因为它存储对副本的引用而不是对原始 的引用x。
| 归档时间: |
|
| 查看次数: |
5530 次 |
| 最近记录: |