首页 > Javascript 的作用域链和垃圾回收问题

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函数内部需要使用的闭包变量,如果是,是在什么时候确定的?


JS引擎有很多不同实现。我没有读过任何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的的时候确定的。不过细节不清楚。

【热门文章】
【热门文章】