saber 酱的抱枕

Fly me to the moon

09/24
2016
学习

使用立即执行函数创建独立作用域

设想网页上有四个按钮:

<input type="button" value="0">
<input type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">

我们用for循环处理它们时,如果要用到它们对应的序号,则可能出现问题。如下JavaScript代码:

var bts=document.querySelectorAll("input");
for (var i = 0; i <= bts.length - 1; i++) {
    bts[i].addEventListener("click",function(){
        alert(i);
    })
}

按照设想,当我们点击按钮时,它们会从左到右分别弹出0/1/2/3,但实际上,全部弹出的是4。这里显而易见有两个问题:
1.为什么弹出的数字都一样;
2.为什么弹出的是4。

其实原因是同一个,那就是for循环里的i是贯穿其整个作用域的。我们给4个按钮分配的i是同一个变量,当这个变量变了的时候,4个按钮上绑定的i都变了。for循环从开始运行到结束,i的值依次是0/1/2/3/4(到4的时候停止运行),最后定格在了4。当我们在for循环执行完之后去点击按钮,i已经是4了,所以全部弹出的是4。

我们可以利用立即执行函数(匿名函数)来创建独立作用域,把每个按钮的事件都在独立作用域里绑定。并且我们绑定时不直接使用i,而是把i的值传递进去进行绑定。这样就可以解决上面的问题。代码如下:

var bts=document.querySelectorAll("input");
for (var i = 0; i <= bts.length - 1; i++) {
    !function(ii){
        bts[i].addEventListener("click",function(){
            alert(ii);
        })
    }(i)
}

这里面除了用立即执行函数包裹了绑定过程,还有个地方要注意,就是这个立即执行函数要有个参数,然后在执行它时把i作为参数传递进去。这样,绑定事件时所使用的ii是具体值,而非变量i。

之后,我们点击按钮,发现依次弹出0/1/2/3,问题得以解决。

使用立即执行函数创建独立作用域