javascript闭包具体解释

今天我们从内存结构上来解说下 javascript中的闭包概念。

闭包:是指有权訪问另外一个函数作用域中的变量的函数。

创建闭包的常见方式就是在一个函数内部创建另外一个函数。

在javascript中没有块级作用域。一般为了给某个函数申明一些仅仅有该函数才干使用的局部变量时,我们就会用到闭包,这样我们能够非常大程度上降低全局作用域中的变量。净化全局作用域。

使用闭包有如上的优点。当然这种优点是须要付出代价的,代价就是内存的占用。

怎样理解上面的那句话呢?

每一个函数的运行,都会创建一个与该函数相关的函数运行环境,或者说是函数运行上下文。这个运行上下文中有一个属性 scope chain(作用域链指针),这个指针指向一个作用域链结构,作用域链中的指针又都指向各个作用域对应的活动对象。

正常情况,一个函数在调用開始运行时创建这个函数运行上下文及对应的作用域链,在函数运行结束后释放函数运行上下文及对应作用域链所占的空间。

比方:

    //声明函数
    function test(){
    var str = "hello world";
    console.log(str);
    }
    //调用函数
    test();

在调用函数的时候会在内存中生成例如以下图的结构:


可是闭包的情况就有点特殊了。因为闭包函数能够訪问外层函数中的变量。所以外层函数在运行结束后,其作用域活动对象并不会被释放(注意。外层函数执 行结束后运行环境和相应的作用域链就会被销毁),而是被闭包函数的作用域链所引用,直到闭包函数被销毁后,外层函数的作用域活动对象才会被销毁。

这也正是 闭包要占用内存的原因。

所以使用闭包有优点。也有坏处,滥用闭包会造成内存的大量消耗。

使用闭包还有其它的副作用,能够说是bug。也能够说不是,相对不同的业务可能就会有不同的看法。

这个副作用是闭包函数仅仅能取到外层函数变量的终于值。

測试代码例如以下:(这里使用了jquery对象)

    /*闭包缺陷*/
    (function($){
    var result = new Array(),
    i = 0;
    for(;i<10;i++){
    result[i] = function(){
    return i;
    };
    }
    $.RES1 = result;
    })(jQuery);
    // 运行数组中的函数
    $.RES1[0]();

上面的代码先通过匿名函数表达式开辟了一块私有作用域,这个匿名函数就是我们上面所说的外层函数,该外层函数有一个參数$,同一时候还定义了变量result和 I , 通过for循环给数组result赋值一个匿名函数。这个匿名函数就是闭包,他訪问了外层函数的变量I , 理论上数组result[i]() 会返回对应的数组下标值,实际情况却不如所愿。

如上代码 $.RES1[0]() 的运行结果是10. 

为什么会这样呢,由于i的终于值就是10.

以下我们通过下图来具体说明下,上面的那段代码运行时在内存中究竟发生了什么:


那么这个副作用有没有办法能够修复呢?当然能够。

我们能够通过以下的代码来达到我们的预期。

    /*修复闭包缺陷*/
    (function($){
    var result = new Array(),
    i = 0;
    for(;i<10;i++){
    result[i] = function(num){
    return function(){
    return num;
    }
    }(i);
    }
    $.RES2 = result;
    })(jQuery);
    //调用闭包函数
    console.log($.RES2[0]());

上面的代码又在内存中发生了什么?我们相同用以下的一幅图来详解。

看懂了上面的图,我们也就不难理解以下的图。


仅仅要看懂上面的三张图,我们也就能够深入的理解清楚javascript中闭包的原理。以及闭包的优点和弊端,在我们的代码中合理的使用闭包,达到代码的整洁和高效。

阅读原文:javascript闭包具体解释

原文地址:https://www.cnblogs.com/gavanwanggw/p/7150300.html