我正在阅读 David Flanagan 的 JavaScript:权威指南,我被困在以下示例中:
window.onload = function() {
var elements = document.getElementsByClassName("reveal");
for(var i = 0; i < elements.length; i++) {
var elt = elements[i];
var title = elt.getElementsByClassName("handle")[0];
title.onclick = function() {
if(elt.className == "reveal") elt.className = "revealed";
else if(elt.className == "revealed") elt.className = "reveal;"
}
}
};
<div class="reveal">
<h1 class="handle">Click Here to Reveal Hidden Text</h1>
<p>This paragraph is hidden. It appears when you click on the title.</p>
</div>
问题是当前形式的代码可以工作,但是如果我要添加多个 div
类 reveal
,无论 h1
元素我点击,只有最后一个会展开。我应该在代码中更改什么才能使其在单独的 div 上工作?
附言我确实知道由于问题的性质是循环内的闭包,所以经常会问这种问题,但是鉴于 SO 上类似问题的解决方案,我无法使我的代码正常工作。谢谢。
最佳答案
在 JavaScript 中,变量作用域是在函数级别设置的。函数创建闭包,它本质上定义了作用域的边界。 子作用域 可以访问定义在父作用域 中的变量,反之则不行。
当您调用 onclick
处理函数,它必须在作用域链中向上查找变量elt
。因为elt
未在当前范围内声明。
范围链中的下一级是您的 window.onload
处理函数(即闭包)。在此范围内,变量 elt
是声明的,它的值由循环设置。 但请记住,当您单击 <h1>
并调用 onclick
处理程序,循环已经终止。因此,elt
将始终是循环中设置的最后一个值。这就是为什么你总是得到 elt
作为最后一个元素。
要解决此问题,您可以使用立即执行函数。立即执行函数创建一个新的闭包(和作用域),其中 elt
在本地声明。因为变量 elt
现在在这个新的内部作用域中声明,它不会被父作用域中的循环修改:
window.onload = function() {
var elements = document.getElementsByClassName("reveal");
for(var i = 0; i < elements.length; i++) {
var elt = elements[i];
var title = elt.getElementsByClassName("handle")[0];
title.onclick = (function(elt) {
return function() {
if(elt.className == "reveal") elt.className = "revealed";
else if(elt.className == "revealed") elt.className = "reveal;"
};
})(elt);
}
};
关于javascript - 修复循环中的闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30990291/