作用域链
每个对象都有一个隐藏属性[[scope]],存放它自身的作用域链,
- GO:全局执行上下文
- AO:函数执行上下文
function test1() {
function test2() {
var b = 2;
}
var a = 1;
test2();
}
var c = 3;
test1();
-
window 是全局作用域,它的 GO 上有 test1 和 c,它的 scope 上只有 GO
-
当 test1()开始执行,就产生了 test1 的 AO,AO 上有 test2 和 a,test1 的 scope 上有自己的 AO 和 window 的 GO,并且会自己的 AO 后占据 GO 的位置,GO 向后排
-
当 test2()开始执行,产生了 test2 的 AO,AO 上有 b,test2 的 scope 上会有自己的 AO,test1 的 AO,全局的 GO。
并且会把自己的 AO 放在第一位,test1 的 AO 和全局 GO 依次向后排
为什么外部作用域不能访问更小的作用域???
链式结构生成:局部作用域越靠内部。自己的 scope 上会有更多的上级 AO(GO 每个作用域都会有),当我们访问变量时,作用域会在 scope 上从自己的 AO 找,如果找不到则向下挨个寻找,直到查询到全局 GO 位置,外部的作用域的 scope 上根本没有更小作用域的 AO,所以每一层的作用域只能访问向上层次的作用域。
闭包
那么问题来了,我要怎么访问局部作用域呢?
function test1() {
function test2() {
var b = 2;
console.log(a);
}
var a = 1;
return test2;
}
var c = 3;
var test3 = test1();
test3();
- 正常执行过程中,当函数执行完毕后,浏览器的内存空间将销毁函数所占用的内存
- 在test1执行中用return返回test2
- 等于是将test2赋给了全局的test3,也就意味着test2可以通过test3执行而执行,test2中的console.log(a),使用了test1中的变量,就会告诉浏览器a我在用,test1执行完毕后不能把a销毁
- 至此,我们在外部拿到了test1作用域中的a。这就完成了闭包的过程
提示
当内部函数被返回到外部并保存时,一定会产生闭包,闭包会导致原来的作用域链不释放。过度使用闭包可能会导致内存泄漏或加载速度过慢