在循环中修复闭包

时间:2015-06-22 21:39:05

标签: javascript closures

我正在阅读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>

问题是当前表单中的代码是有效的,但是如果我要添加多个divreveal,那么无论我点击什么h1元素在,只有最后一个将扩大。我应该在代码中更改它以处理单独的div?

P.S。我确实理解这个问题是经常被问到的,因为问题的本质是循环中的闭包,但是我不能让我的代码在SO上提供类似问题的解决方案。谢谢。

1 个答案:

答案 0 :(得分:4)

在JavaScript中,变量范围设置为功能级别。函数创建闭包,它实质上定义了范围的边界。 子范围可以访问父范围中定义的变量,但不能反过来。

当您调用onclick处理函数时,它必须向上 范围链才能找到变量elt,因为{{1} }未在当前范围内声明。

范围链中的下一级是你的elt处理函数(即闭包)。在此范围内,变量window.onload 声明为,其值由循环设置。 但请记住,当您点击elt并调用<h1>处理程序时,循环已终止。因此,onclick将始终是循环中设置的最后一个值。这就是为什么你总是将elt作为最后一个元素。

要解决此问题,您可以使用立即执行功能。立即执行函数创建一个新的闭包(和范围),其中elt在本地声明。因为变量elt现在在这个新的内部作用域中声明,所以它不会被父作用域中的循环修改:

elt