JS-从上下文和作用域链观察闭包

先上一个闭包:

 var a = 'global'
 function outerFunc() {
        var b = 'outer 1'
        var c = 'outer 2'

        function innerFunc() {
            var d = 'inner'
            console.log(a) //内部函数用到a和b,但没有用到c
            console.log(b)
            return true
        }
        return innerFunc
    }

 var result = outerFunc()
 console.log(result())

看chrome中这段代码的内存快照
图1,outerFunc指向@4697号上下文,@4697内含全局变量 a ,因此@4697是全局作用域。

1.png

图2,innerFunc指向@4683@4683(outerFunc)→@4697(全局)。innerFunc根据作用域链找到 ab

2.png

但是,照道理,图3这句代码执行之前,outerFunc的上下文已经出栈,为什么innerFunc还能指向4683,却又看不到变量c呢?

3.png

分析:
开始运行outerFunc()时的情况:(图都写成let了,这里不区别词法环境)

4.PNG

5.png

outerFunc运行完后,返回innerFunc,让result引用innerFunc这个函数。这时outerFunc上下文出调用栈,移到堆上。一段时间后,垃圾回收机制启动,检查outerFunc上下文及内部所有引用的变量,发现b被引用的情况是 : result→innerFunc→b,因此b被留下。而 c 完全没被引用,c 被回收。而outerFunc的上下文被innerFunc引用,也保留。

只要result不释放,outerFunc上下文和innerFunc上下文就会一直保留。

对比一下:如果outerFunc内部定义的函数innerFunc没有用到outerFunc的变量。(将console.log(a)注释掉)

 var a = 'global'
 function outerFunc() {
        var b = 'outer 1'
        var c = 'outer 2'

        function innerFunc() {
            var d = 'inner'
            //console.log(a) //内部函数用到a和b,但没有用到c
            console.log(b)
            return true
        }
        return innerFunc
    }

 var result = outerFunc()
 console.log(result())

innerFunc的context指向的是全局上下文,而outerFunc上下文及它引用的变量因为没被执行环境引用,被垃圾回收了。


6.png

目前的理解,有待改进。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容