分析一段代码的创建执行过程
1 | var y = 10; |
对于上述代码的执行过程:
在执行全局代码前,创建全局上下文即:1
2
3
4
5globalEC = {
this: window,
vo: window,
sc: [winodw]
}
注:凡是创建上下文,总会有三个属性,this、vo、sc。
接下来进行变量实例化:在变量实例化时所有变量均为undefined,同时会创建test函数(testFun),由于在函数创建时确定函数的scope,
而函数的scope为函数创建时所在上下文的作用域链,testFun函数是在全局上下文中创建,所以testFun[[scope]]为globalEC.sc——[window]1
2
3
4
5vo:{
y: undefined,
fun: undefined,
test: testFun
}
全局代码执行:
首先 var y = 10; window的y属性由undefined变为101
2
3
4
5vo:{
y: 10,
fun: undefined,
test: testFun
}
接下来到 var fun = test();
执行test函数时,创建test函数的函数上下文即:1
2
3
4
5testEC = {
this: window,
vo: testAO,
sc: [testAO, testFun.[[scope]]] = [testAO, window]
}
注:函数上下文的作用域链始终包含两个元素,当前激活对象和当前函数的[[scope]]。
激活对象就是testAO,而函数的[[scope]]则是当前函数创建时所在的上下文的作用域链,所以testEC的作用域链为[testAO,window]。
接下来变量实例化:1
2
3testAO: {
y: undefined
}
实例化后接着函数代码执行:
首先var y = 2; testAO.y值由undefined 变为 21
2
3testAO: {
y: 2
}
接着执行:1
2
3return function(){
alert(y);
}
创建匿名函数nFun:上面说到了创建函数的时候回确定函数的[[scope]],由于它是在test函数中创建的,所以nFun[[scope]] = testEC.sc = [testAO, window]
执行完fun = test()后,fun由undefined变为nFun
全局上下文中的变量对象1
2
3
4
5vo:{
y: 10,
fun: nFun,
test: testFun
}
接着执行fun();
前面说到了在函数执行之前,会创建函数上下文:它是在test函数中被创建的,所以nFun的作用域链为当前激活对象+test函数的上下文的作用域链。1
2
3
4
5nFunEC = {
this: window,
vo: nAO,
sc: [nAO, nFun[[scope]]] = [nAO, testAO, window]
}
最后执行alert(y)
从nFunEC.sc中查找y
在testAO中找到且值为2