js引擎执行过程

分析一段代码的创建执行过程

1
2
3
4
5
6
7
8
9
var y = 10;
function test(){
var y = 2;
return function(){
alert(y);
}
}
var fun = test();
fun();

对于上述代码的执行过程:
在执行全局代码前,创建全局上下文即:

1
2
3
4
5
globalEC = {
this: window,
vo: window,
sc: [winodw]
}

注:凡是创建上下文,总会有三个属性,this、vo、sc。
接下来进行变量实例化:在变量实例化时所有变量均为undefined,同时会创建test函数(testFun),由于在函数创建时确定函数的scope,
而函数的scope为函数创建时所在上下文的作用域链,testFun函数是在全局上下文中创建,所以testFun[[scope]]为globalEC.sc——[window]

1
2
3
4
5
vo:{
y: undefined,
fun: undefined,
test: testFun
}

全局代码执行:
首先 var y = 10; window的y属性由undefined变为10

1
2
3
4
5
vo:{
y: 10,
fun: undefined,
test: testFun
}

接下来到 var fun = test();
执行test函数时,创建test函数的函数上下文即:

1
2
3
4
5
testEC = {
this: window,
vo: testAO,
sc: [testAO, testFun.[[scope]]] = [testAO, window]
}

注:函数上下文的作用域链始终包含两个元素,当前激活对象和当前函数的[[scope]]。
激活对象就是testAO,而函数的[[scope]]则是当前函数创建时所在的上下文的作用域链,所以testEC的作用域链为[testAO,window]。
接下来变量实例化:

1
2
3
testAO: {
y: undefined
}

实例化后接着函数代码执行:
首先var y = 2; testAO.y值由undefined 变为 2

1
2
3
testAO: {
y: 2
}

接着执行:

1
2
3
return function(){        
alert(y);
}

创建匿名函数nFun:上面说到了创建函数的时候回确定函数的[[scope]],由于它是在test函数中创建的,所以nFun[[scope]] = testEC.sc = [testAO, window]

执行完fun = test()后,fun由undefined变为nFun
全局上下文中的变量对象

1
2
3
4
5
vo:{
y: 10,
fun: nFun,
test: testFun
}

接着执行fun();
前面说到了在函数执行之前,会创建函数上下文:它是在test函数中被创建的,所以nFun的作用域链为当前激活对象+test函数的上下文的作用域链。

1
2
3
4
5
nFunEC = {
this: window,
vo: nAO,
sc: [nAO, nFun[[scope]]] = [nAO, testAO, window]
}

最后执行alert(y)
从nFunEC.sc中查找y
在testAO中找到且值为2