Javascript 的作用域链和垃圾回收问题
天蓬老师
天蓬老师 2017-04-10 17:16:04
[JavaScript讨论组]

有如下代码:

function f1(){
    var a1 = 1;
    var b1 = 2;
    var c1 = 3;
    function f2(){
        var a2 = a1;
        function f3(){
            var a3 = b1;
            return a3;
        }
    }
    return f2;
}
var f = f1();
...

两个自认为密切相关的问题的问题:
1、假如在var f = f1();之后垃圾回收器被触发,f1被调用时生成的局部变量是全部被保留,还是c1会被回收?
2、f1函数返回的时候,js引擎是否能够确定f2函数内部需要使用的闭包变量,如果是,是在什么时候确定的?

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

全部回复(2)
黄舟

JS引擎有很多不同实现。我没有读过任何JS引擎的源码,所以不敢乱说。只从ES规范的角度简单说一下。

  • 问题一:
    c1保留还是不保留都是可以的。方案一:c1保留;方案二:c1不保留。不过根据我对Chrome浏览器的测试,c1不会保留,说明webkit引擎采取了方案二。

  • 问题二:
    与问题一中两种方案采取哪一种有关。假设某个JS引擎采取了方案一,那么问题就简单了。根据ES规范:

函数对象中有一个指向外部词法环境的引用(指针)。

根据我的理解,这是形成闭包的根本原因。也就是说,在f2被定义的时候,f2这个函数有一个叫做f2.scope的内部属性。它指向定义f2这个函数的词法环境,也就是f1执行时生成的词法环境,这个词法环境里面保存了a1、b1和c1等变量。所以在f1执行完返回后,只要f2还存在,它仍然可以访问f1的局部变量。这里面的基本原理就是:

被引用的变量不会被垃圾回收。

所以,假设JS引擎采取方案一,那么它根本不用关心f2用到了f1的哪些局部变量。你用到谁时自己去取就是了,反正它们一直都存在。

但是如果采取方案二(为了不让那些不需要的局部变量占内存),那么JS引擎实现起来就麻烦一些了,我猜它会在f1返回前去扫描内部的函数定义,例如f2和f3的源码,以确定哪些变量没有被内部函数引用,可以释放了。为什么是函数返回前去扫描呢?因为我们知道,函数返回前正是释放局部变量的时候嘛。

当然,由于f1可能会被调用很多次,从而返回很多次。不能每次都傻乎乎地扫描一遍啊。所以JS引擎可能只在第一次返回时扫描,然后把结果记录在f1的一个内部属性里面就行了,后面再调用时直接读取这个内部属性就好了。

高洛峰

1,c1会被释放
2,可以确定。我理解是在解释js的的时候确定的。不过细节不清楚。

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

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