函数闭包问题的学习

在前端面试中时常会被问到闭包这个概念,那么闭包到底是什么呢?怎么去解读这个概念呢?
其实在别的编程语言里面有代码块级作用域这么一个概念,但是在JS中,不在一个代码块内的变量是可以被访问跟修改的,为了保护这些私有变量不受外界的改变,所以就有了闭包这个概念。
<ul id="myUl">
    <li>111</li>
    <li>222</li>
    <li>333</li>
</ul>
<script>
    var myUl=document.getElementById("myUl");
    var myLi=myUl.getElementsByTagName("li");
    for(var i=0;i<myLi.length;i++){
        myLi[i].onclick=function(){
            alert(i+1);
        }
    }

这里的alert就会直接弹出4,因为for循环里面的那个匿名函数,是个异步事件,也就是说代码,顺序执行时,不会执行这个函数,只有当触发事件产生,才会执行这个函数,而此时的循环早已结束,此时的i已经为3,所以弹出4。此时应用闭包就可以解决问题,其实严格的说,只要是定义了一个函数,这个函数执行时就产生了闭包,闭包只是一种运行机制。

var myUl=document.getElementById("myUl");
    var myLi=myUl.getElementsByTagName("li");
    for(var i=0;i<myLi.length;i++){
        ;(function(i){
            myLi[i].onclick=function(){
                alert(i+1);
            }
        })(i)
    }
 var myUl=document.getElementById("myUl");
    var myLi=myUl.getElementsByTagName("li");
    for(var i=0;i<myLi.length;i++){
        myLi[i].onclick=(function(i){
            return function(){
                alert(i+1);
            }
        })(i)
    }

修改成上述两种方式都可以,函数在执行的时候,就会形成一个私有作用域,而这个作用域里面定义的参数,是不受外界干扰的。解决异步,即保护作用域里面的参数不受外界的干扰。
关于定时器以setTimeout为例

window.setTimeout(fn(),1000);

此时,会直接执行fn(),并将fn的返回值,加入到setTimeout的队列中,
而且setTimeout天生就是一个异步的。可看一下代码,可见 闭包是处理异步的非常好用的方法。

for(var i=0;i<myLi.length;i++){
       window.setTimeout((function(i){
           return function(){myLi[i].style.left=100*(i+1)+"px";
           }
       })(i),(i+1)*1000)
    }

关于函数作用域的释放问题,一般情况下当一个函数执行完之后,这个函数所创建的作用域,将会消失,当这个函数再次执行时,会再 创建一个作用域,前后两个作用域不干扰。若这个函数中产生了闭包,且这个闭包被一个时间绑定,或者返回给了一个变量,那么这个函数创建的作用域将不会消失。

function fn(){
    var i=0;
    return function(){
        console.log(i++);
    }
}
var a=fn();
a();
a();

两次打印分别为0和1。是因为 返回的函数赋给了变量,在var a=fn()这一句中函数所创建的作用域就不会被释放。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章