首页 > 关于闭包引申出的问题

关于闭包引申出的问题

第一次代码

<body>
    <div class="div_area" id="1">1</div>
    <div class="div_area" id="2">2</div>
    <div class="div_area" id="3">3</div>
    <div class="div_area" id="4">4</div>
    <div class="div_area" id="5">5</div>

    <script>    
        var div=document.getElementsByClassName("div_area");
        for(var i=0;i<div.length;i++){
            div[i].onclick=function(){
                alert(div[i].id);
            }        
        }
       
    </script>
</body>

这段代码无法实现点击div输出div的id,因为i的值时5,但是我不明白的是为什么i的值是5,这是因为js没有块级作用域导致的还是闭包(看起来不是闭包啊,闭包最常见创建方式的不是函数内嵌函数吗,这里只有一个函数啊)

于是我把代码修改了以后为什么就又可以了?
第二次代码:

 alert(this.id);

接着我又把js代码改成了这样,创造了一个闭包,结果i的值也是5,所以DOM找不到,我想问造成i=5的原因和第一次的时候是否时一样的?

第三次代码:


<script>
    
        var div=document.getElementsByClassName("div_area");
        function add(){
            for(var i=0;i<div.length;i++){
                div[i].onclick=function(){
                    alert(div[i].id);
                }
        
            }
        }
    add();
       
    </script>

这个就是闭包。

闭包不一定必须是两个函数嵌套,而是两个词法环境嵌套。只不过函数是最常见的可以形成词法环境的词法结构。

除了函数外,全局上下文、with语句、catch子句都可以形成词法结构,从而构成闭包。


SegmentFault 上已经出现若干关于类似的装闭包问题了。
闭包一定要注意变量的作用域,因为你的闭包中一直都是用的同一个变量 i,而 i 是变化的,所以最好到使用的时候都是 i 的终值。

for (var i = 0; i < div.length; i++) {
    div[i].onclick = (function(n) {
        return function() {
            alert(div[n].id);
        }
    })(i);
}

其实可以不用闭包,因为在 onclick 函数里直接用 this 就是绑定事件的那个 div 啊。

for (var i = 0; i < div.length; i++) {
    div[i].onclick = function() {
        alert(this.id);
    }
}

因为你onclick执行的时候,循环肯定早就执行完了,这时i为5。你可以试试改成立即执行的函数,是不是感觉正常了?

for(var i=0;i<3;i++){
    (function(){
        alert(i);
    })()
}

少年郎...建议你先去看《JavaScript 高级程序设计》第七章...你就懂啥是闭包了...

没有书也没关系...可以看别人归纳的读书笔记...比如我的~= ̄ω ̄=~

然后做一做常见的面试题...比如这篇

关于 this 指针的指向问题推荐看看《JavaScript秘密花园》


这个我来说说吧。
①因为你在for循环中。i 始终都是一个变量。在开始注册事件的时候,每个div对象的onclick属性都是一个函数,并且这个函数是

function(){
    alert(div[i].id)
}

,没错,这里是div[i].id,i的值还不确定。这里还没执行的。执行的条件就是你在浏览器点击了div,这时在内部循环已经完成该了。i=5。
②每个onclick事件执行时,this会绑定到点击它的dom元素。更详细的解释:每个div都是一个对象,onclick是它的属性,类似

div[i] = {
        onclick:function(){alert(this.id)}
}

,所以这个this隐式绑定到div[i]上。点击的时候会找到这个div的id属性。你可以把id的值换了试一试。
③和1是一样的。并不是闭包。闭包的概念:是在当前的作用域能使用其他作用域。这里可以使用一个即时函数(IIFE)。

var div=document.getElementsByClassName("div_area");
for(var i=0;i<div.length;i++){
    div[i].onclick=(function(count){
            return function(){
                alert(div[count].id)
            }
    })(i)
}

如果还有什么不明白可以追问喔。答得不好的请多多包涵:)
----二次更新
一和三都不是闭包(个人看法)。如下代码

function foo(){
    var a = 2;
    
    function bar(){
        console.log(a);
    }
    return bar;
}
var baz = foo();
baz();//2..

以上就是闭包。
解释如下:函数bar()的词法作用域能够访问foo()的内部作用域。然后将bar函数本身当作一个值类型进行传递。bar显然可以正常执行,在这个例子中,它在自己定义的词法作用域以外的地方执行。

在foo()执行后,通常会期待foo()的整个内部作用域被销毁(js的垃圾回收器)。

而闭包的"神奇"之处是可以阻止这件事情的发生。因为在bar()声明的地方,它拥有涵盖foo()内部作用域的闭包,使得该作用域能够一直存在,以供bar()在之后任何时间进行引用。
bar()依然持有对该作用域的引用,而这个引用就是闭包。
-----------------------------以下为书中原话(译版)

当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前的词法作用域之外执行。下面用一些代码来解释这个定义。

function foo(){
    var a = 2;
    
    function bar(){
        console.log(a);//2
    }
    
    bar();
}

foo();

这段代码看起来和嵌套作用域中的实例代码很相似。基于词法作用域的查找规则,函数bar()可以访问外部作用域的变量a(这个例子中的是一个RHS引用查询)。
这是闭包吗?
技术上来讲,也许是。但根据前面的定义,确切地说并不是。我认为最准确地用来解释bar()对a的引用的方法是词法作用域的查找规则,而这些规则只是闭包的一部分。(但却是非常重要的一部分!)

上面是书中原话。最后一段解释我感觉很模棱两可。可能是翻译的原因或者我没理解。
书名:你不知道的JavaScript上卷 没找到英文版,哪位找到发我一份啊。。谢谢啦!


本质上是一样的。

在执行alert(div[i].id);的时候,for循环已经完成,i的值已经变成5了。而this绑定的始终是被点击的对象。

【热门文章】
【热门文章】