但如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当做垃圾回收。

发布于 2022-09-06 12:37:05 字数 2330 浏览 17 评论 0

js 权威指南-第六版-中 p184 实现闭包,有段话理解不了;全文是这样:

每次调用 js 函数时,都会为之创建一个新的变量对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回时,就从作用域链中将这个绑定的变量对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,他就会被当做垃圾回收掉。如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当做垃圾回收。但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数,他就不会被当做垃圾回收,并且他所指向的变量绑定对象也不会被当做垃圾回收。

我分成三段理解:

1、每次调用 js 函数时,都会为之创建一个新的变量对象用来保存局部变量,把这个对象添加至作用域链中。当函数返回时,就从作用域链中将这个绑定的变量对象删除。如果不存在嵌套的函数,也没有其他引用指向这个绑定对象,他就会被当做垃圾回收掉。

可以理解上面一段,下面两段不太清楚;

2、如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当做垃圾回收。

3、但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数,他就不会被当做垃圾回收,并且他所指向的变量绑定对象也不会被当做垃圾回收。

结合高程,可以理解3、,因为换成代码就是这样:

function createComparisonFunction(propertyName) {
    //并将它作为返回值返回
    return function(object1, object2) {
        var value1 = object1[propertyName];
        var value2 = object2[propertyName];
        if (value1 < value2) {
            return -1;
        } else if (value1 > value2) {
            return 1;
        } else {
            return 0;
        }
    };
}

//创建函数
var compareNames = createComparisonFunction("name");

createComparisonFunction()函数在执行完毕后,其活动对象也不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。这个很好理解;

但是2、比较模糊,换成代码我觉得就是下面这样,

function createComparisonFunction(propertyName) {
    //但如果这些嵌套的函数对象在外部函数中保存下来
    function f(object1, object2) {//嵌套的函数都各自对应一个作用域链
        var value1 = object1[propertyName];//这个作用域链指向一个变量绑定对象
        var value2 = object2[propertyName];
        if (value1 < value2) {
            return -1;
        } else if (value1 > value2) {
            return 1;
        } else {
            return 0;
        }
    }

    return f;
}

var compareNames = createComparisonFunction("name");

所以问题是:
var compareNames = createComparisonFunction("name"); 执行完了后,createComparisonFunction()的活动对象会被销毁么?

回答1:会销毁,因为按照 2、所说,

但如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当做垃圾回收。

返回的 f 在 外部函数中保存下来了,所以会和所指向的变量绑定对象一样当做垃圾回收。

回答2:不会销毁,因为返回的 f 里依然保存着对 createComparisonFunction() 活动对象的引用啊,就是那个 propertyName ,所以 createComparisonFunction() 活动对象不会销毁;

所以哪个解释是对的?还是有其他解释?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

趴在窗边数星星i 2022-09-13 12:37:05

如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当做垃圾回收。

一共两句话。前面那句只是说嵌套函数也有自己的作用域链和变量绑定对象,所以主要是后面那一句。这句话的意思是,外部函数可以在其变量绑定对象中保存嵌套函数的引用,但是如果没有把嵌套函数返回给其他代码,那么当外部函数销毁的时候,其保存的嵌套函数也会同时被销毁回收。

翻译成代码是这样的:

function outer() {
    var a = 3;
    function inner() {
        var b = 5;
    }
    // 这时候outer的变量绑定对象里面有a和inner两个变量
    // 所以当outer被回收的时候,a和inner也会被同时回收

    ...
}

第三段话则比上面这段话的意思更进了一步。

但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数,他就不会被当做垃圾回收,并且他所指向的变量绑定对象也不会被当做垃圾回收。

如果innerouter作为返回值返回的话,那么就不仅仅是outer保有它的引用了,外面会有其他变量也保有它的引用。所以当outer被回收的时候,inner并不会回收。

挽袖吟 2022-09-13 12:37:05

2、如果定义了嵌套的函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链指向一个变量绑定对象。但如果这些嵌套的函数对象在外部函数中保存下来,那么他们也会和所指向的变量绑定对象一样当做垃圾回收。
3、但是如果这个函数定义了嵌套的函数,并将它作为返回值返回或者存储在某处的属性里,这时就会有一个外部引用指向这个嵌套的函数,他就不会被当做垃圾回收,并且他所指向的变量绑定对象也不会被当做垃圾回收。

意思说当一个函数返回一个函数对象,并且这个还是赋值了一个外部变量,那么当这个外部变量不再被其引用,也就是符合垃圾回收的条件(非活动对象)时,将被回收掉。如果这个外部变量一直保持有对返回的函数的引用,那么这个函数对象就不会被回收掉

其实上面2段函数是一样的,

var compareNames = createComparisonFunction("name");
//执行一些操作
compareNames(....);
compareNames=null;
//此后createComparisonFunction返回的对象不再被引用,就会在某个时刻被GC掉
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文