先上一个闭包:
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根据作用域链找到 a 和 b。
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
目前的理解,有待改进。