我正在阅读David Flanagan的 JavaScript:The Definitive Guide ,我坚持以下示例:
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?
P.S。我确实理解这个问题是经常被问到的,因为问题的本质是循环中的闭包,但是我不能让我的代码在SO上提供类似问题的解决方案。谢谢。
答案 0 :(得分:4)
在JavaScript中,变量范围设置为功能级别。函数创建闭包,它实质上定义了范围的边界。 子范围可以访问父范围中定义的变量,但不能反过来。
当您调用onclick
处理函数时,它必须向上 范围链才能找到变量elt
,因为{{1} }未在当前范围内声明。
范围链中的下一级是你的elt
处理函数(即闭包)。在此范围内,变量window.onload
声明为,其值由循环设置。 但请记住,当您点击elt
并调用<h1>
处理程序时,循环已终止。因此,onclick
将始终是循环中设置的最后一个值。这就是为什么你总是将elt
作为最后一个元素。
要解决此问题,您可以使用立即执行功能。立即执行函数创建一个新的闭包(和范围),其中elt
在本地声明。因为变量elt
现在在这个新的内部作用域中声明,所以它不会被父作用域中的循环修改:
elt