我们都知道,js的执行顺序总是与代码的先后顺序有所差异,抛开异步的问题,我们会发现就算是同步,代码的执行结果也总和我们的预期不相符合,这是js预编译的效果。提到预编译就不得不提作用域链。
作用域链:[[scope]]中以链式连接的形式存储着执行期上下文,是一个隐式属性。多次调用同一个函数会创建多个执行器上下文,每次执行完都会被销毁。
举个栗子:
function a() {
function b() {
function c() {}
}
}
上面这个简单的栗子,[[scope]]的变化过程大概是这样的
首先a被定义,这时候
a.[[scope]] {
0:Go
}
然后a变量执行
a.[[scope]] {
0:aAo
1:Go
}
同上b被定义
b.[[scope]] {
0:aAo
1:Go
}
b被执行
b.[[scope]] {
0:bAo
1:aAo
2:Go
}
c被定义
c.[[scope]] {
0:bAo
1:aAo
2:Go
}
c被执行
c.[[scope]] {
0:cAo
1:bAo
2:aAo
3:Go
}
在例如:
function a() {
var num=100;
function b() {
numm++;
console.log (num);
}
return b;
}
var demo= a();
demo()
demo()
答案: 101 102
变量a定义执行之后scope中有aAo,Go
然后b被定义,bAo就拿到了aAo的成果,这个时候b没有被执行,而是被保存到了外部,并在外部执行。num++ 得到结果101,执行完之后,bAo被销毁,但num存储在aAo中。第二次调用demo的时候,会形成新的bAo,执行num++,结果为102.
内部的函数被保存到了外部,这就形成了闭包。