javascript - 闭包中外层函数未被直接引用的变量何时被 GC 回收
ringa_lee
ringa_lee 2017-04-10 14:26:24
[JavaScript讨论组]

举一个简单的闭包例子:

function A() {
    var i = 1;
    var j = 2;
    return function(){
        return i;
    }();
}

var B = A();

在语句 return i 这一行设置断点,调试如下:

之前看过有关闭包的资料时知道由于函数 A 中的变量被引用,所以函数 A 不会被 GC 回收,那么这个不回收指的是整个函数 A 都不会被回收,还是被直接引用的部分不会被回收呢?
再举一例:

function A() {
    var i = {x : 1};
    var j = i;
    return function(){
        return j;
    }();
}

var B = A();

此时,ij 引用,所以 ij 指向同一个内存空间,但是断点调试时依然访问不到未被直接引用的变量 i

我的猜想是,当我设置断点进行调试时由于是全局作用域,所以我访问不到外层函数内部未被闭包暴露在全局作用域下的变量,而并不是因为该变量已经被 GC 回收了。

那么我最终的问题是:未被闭包直接引用的外层函数的变量在我设断点调试时到底有没有被 GC 回收呢?如果未被回收,为何我调试时访问不到呢?是因为作用域的问题吗?如果此时未被回收,那么该变量何时会被回收呢?

FirefoxSafari 调试时居然是可以访问到未引用的变量 j 的,截图如下:

1.Firefox

2.Safari

现在基本明白了,可能是 debugger 的问题?

测试代码如下:

var v0 = 'i am at level 0';
var f1 = function () {
    var v1 = 'i am at level 1';
    var f2 = function (){
        var i = 1;
        var j = 2;
        var f3 = function (){
            console.log(i);
        }
        f3();
    }
    f2();
}
f1();

Chorme

Firefox


Safari

ringa_lee
ringa_lee

ringa_lee

全部回复(1)
怪我咯

撸主两个问题,我答第二个吧,什么时候回收, 这个很有意思
A closure is a function that “captures” values near where it was born
closure 是在生成是“捕获”他周围值的函数。

所以,捕获的意思是 cache,还是 reference 呢:
例1:值?

function add(aNumber){
    return function(anotherNumber){
        console.log((anotherNumber+aNumber));
    };
}

var param = 11;
var addByEleven = add(param);
addByEleven(1) // => 12
param = 0;
addByEleven(1) // =>  12

好像 捕获 的是值啊?慢着
例2:也好像是引用啊?

function add(aNumber){
    return function(anotherNumber){
        console.log((anotherNumber+aNumber.value));
    };
}

var param = {value:11};
var addByEleven = add(param);
addByEleven(1) // => 12
param.value = 0;
addByEleven(1) // =>  1

所以,可以理解为捕获的是 reference 吗?有意思的来了

param = {value:2}

将 param 附一个新对象,意思旧的传入 add 的对象没有 ref 是不是会回收呢?看一下输出

addByEleven(1) // =>  1

还是1,惊呆了,不是报错,也不是新对象的值,说明 closure 也有一个最初传入 add 函数的参数引用,那个参数的对象还在内存中,而且现在只有 closure 引用他,因此不会被回收,这里也不会报错。

结论

closure “捕获”意思是,引用实际对象,也就closure中的aNumber实际上引到参数对象/值,所以改变传入的 param 引用不会影响 closure 的引用。因此只有 closure 没有引用时例子里则是addByEleven=null,才会释放.

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号