js之闭包

js中的闭包是一个比较常见的核心概念,之前我们讲的重载,函数柯里化中都用到了闭包,那么到底什么才是闭包呢,闭包能为我们干嘛呢?

按照js犀牛书的定义,闭包是指函数变量可以保存在函数作用域内,这句话的意思貌似太笼统了,而且范围很广,一般的函数内都会包裹变量,那么也可以说有变量的函数就叫闭包吗?显然不是,我们看下js高程里的定义

闭包是指有权访问另一个函数作用域中的变量的函数,这就是说访问外层函数变量的内层函数就叫作闭包咯。那么我们换一种意思理解,闭包是指那些在当前作用域上的函数或者变量被下层作用域所调用,那么我们先来看一个简单的闭包

 function a(){
             var c= 2;
             var b = function(){
                 console.log(c);
             }
             b();
         }
         a(); //输出2

在上面的函数中,我们声明定义了一个a()函数,在函数里有个变量c ,该变量被内层函数b()使用输出,最后调用内层函数b();那按照上面的定义,因为在b的作用域内,调用了属于a作用域内的变量,所以形成了闭包。我们通过分析执行环境来看一下闭包的过程

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

首先,进入全局执行环境,foo()和test()进行变量声明,然后进入第十行执行foo()函数,此时进入foo的执行环境

首先a 和bar()先进行声明,然后执行第六行代码tes(bar) ,此时进入作用域链进行查询,查询test(),在全局作用域中找到test,然后进人test执行环境,然后执行bar,向上foo中查找bar,找到bar,然后执行console,此时console是全局自带的,在全局执行环境中找到,然后查找a,在foo执行环境中找到a,最后输出2;这样一来,我们就能很清楚的弄清楚闭包了,在局部函数中,变量通常会在函数执行后就会消失,但因为有闭包存在,闭包变量在别的作用域中被调用,所以a不会消失,成为自由变量,直到被再次找到,闭包会造成内存泄漏也是此原因。

最后我们留一道题目给大家思考,看一下对闭包的理解是否到位

for (var i=1; i<=5; i++) { 
    setTimeout( function timer() {
        console.log(i);
    }, i*1000 );
}

上面的代码会输出5个6,那么如何才能输出1,2,3,4,5呢? 这里提示一下,这里的for循环在执行时会生成5个定时器,然后定时器在沿着作用域链上去查找i,而此时的i的值可能跟你预想不一样,这里需要用到闭包来做。

下回给大家讲下作用域。

posted @ 2018-12-01 10:46  矛小盾  阅读(169)  评论(0编辑  收藏  举报