通俗讲解闭包

前言:什么是闭包?它有什么优点缺点?这是很多公司面试时候总是问的装逼问题,因为闭包这种东西其实我们大家都用过,就是不知道名词。网上的答案也是五花八门,有的答案啰嗦,有的答案过于简洁。至于优点缺点更是说的模棱两可,让人只知其意,不知其义。

1.什么是闭包?

  说破了大天,其实就是:子函数用了父函数里面定义的参数、变量。

  闭包的原理:每个函数在声明并执行的时候,ECMAScript都会为该函数在作用域链上追加上一个该函数的作用域,该作用域中保存了该函数的 引用对象局部变量的指针,如果不存在闭包,那么每个函数的作用域都包含在window对象的这个大作用域中,当关闭浏览器,window这个东西才被销毁。而有了闭包,就会形成子函数的作用域被包在父函数的作用域中,而父函数的作用域又被包在了window中。当形成闭包的子函数调用参数的时候,会通过检索变量名称,逐级上溯。先找自身,再找父函数,没有再找window。

2.怎么分辨闭包?

   但是闭包也不能靠是否函数包着函数来分辨,比如下面这个例子:

  

var res = new Array();
        function creat() {
            for (var i = 0; i < 10; i++) {
                res[i] = function () {
                    return i;
                };
            }
        }
        creat();
        alert(res[2]());//输出10

 这里面虽然函数包着函数,但是在该作用域中,匿名函数并没有运行,只是起到了定义的作用,并作为一个变量赋值给了数组,而当数组再运行该匿名函数的时候,creat函数已经运行完毕,作用域中保存的都是变量的指针,而不是变量的值,所以当匿名函数运行返回i时,i已经指向10这个数值。
 而在creat中就运行匿名函数的时候,数组就会保存 0-9的数字,虽然用到了闭包,但是这跟我们数组保存函数这一初衷相违背,所以,我们可以在给数组赋值这一过程的时候给它加上闭包

var res = new Array();
        function creat() {
            for (var i = 0; i < 10; i++) {
                res[i] =function(num){ 
                  return  function () {
                        return num;
                     }
                  }(i);
            }
        }
        creat();
        alert(res[2]());//输出2

这样大家就能理解闭包了吧。

3.闭包的优点是啥?

方便大家编程,函数嵌套省去了函数间来回来去的传参,我就不信

function father(a,b){
   var arr=new Array();
   arr.push(a+b);
   arr.push(a-b);
   return arr;
}
function father2(){
    return father(3,2)[0]*father(3,2)[1];
}
alert(father2());//5

这样写比这样写看着更简洁,更省代码量。

function father(a, b) {
            function son() {
                return (a + b) * (a - b);
            }
            return son();
        }
        alert(father(3,2));//5

而且相互调用参数的层次以及函数作用域看得更为明显,保持变量在逻辑上的连贯性,而不是让人看传参看得眼花。保持了变量的私有性,极好的避免了变量重名冲突。方便了开发。

4.闭包的缺点

闭包的优点同时也是它的缺点,保持变量逻辑上的连贯性必然导致ECMAScript下函数作用域链的延长,占用内存空间。

原因:函数包着函数就导致作用域链又加了一环,比如上述例子:

        方案一有两个函数作用域,但是二者没有指向关系,father函数执行完毕,作用域销毁,传递给father2数据,father2在执行完后销毁。

        方案二,father函数包着son函数,father执行时不同时启动了son函数,son函数的作用域引用了father作用域的变量对象,所以father函数得等着son函数执行并销毁完它才能销毁。

         还有缺点就是在变量的生存周期上,占用了内存。

        方案一:father执行完后,a,b作为非全局变量被销毁。

        方案二:father的a,b变量在等待son函数使用完a,b后才能销毁。

        

posted @ 2013-12-30 20:04  白菜帮子  阅读(613)  评论(0编辑  收藏  举报