在《深入--词法作用域与动态作用域》中,提出这样一道思考题
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f(); } checkscope();
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope()();
两段代码都会打印‘local scope’,虽然两段代码执行的结果一样,但是两段代码究竟有哪些不同呢?
紧接着就在《深入--执行上下文栈》中,讲到了两者的区别在于执行上下文栈的变化不一样,然而回答的太笼统,本片详细解析执行上下文栈和执行上下文具体变化过程
具体执行分析
第一段代码执行过程:
1.执行全局代码,创建全局执行上下文,全局执行上下文被压入执行上下文栈
ECStack = [ globalContext ];
2.全局上下文初始化
globalContext = { VO:[global,scope,checkscope], Scope:[globleContext.VO], this:globleContext.VO }
3.全局上下文初始化的同时,checkscope函数被创建,保存作用域链到函数的内部属性[[scope]]
checkscope.[[scope]] = [ globalContext.VO ];
4.执行checkscope函数,创建checkscope函数执行上下文,并压入栈
ECStack = [ checkscopeContext, globalContext ];
5.checkscope函数执行上下文初始化:
①复制函数[[scope]]属性创建作用域链
②用arguments创建活动对象
③初始化活动对象,即加入形参、函数声明、变量声明
④将活动对象压入checkscope作用域链顶端
同时f函数被创建,保存checkscope作用域链到f函数内部属性[[scope]]
checkscopeContext = { AO:{ arguments:{ length:0 }, scope:undefined, f:reference to function f(){} }, Scope:[AO,globalContext.VO], this:undefined }
6.执行f函数,创建f函数执行上下文并压入栈
ECStack = [ fContext, checkscopeContext, globalContext ];
7.f函数执行上下文初始化,跟上面一样:
①复制函数[[scope]]属性创建作用域链
②用arguments创建活动对象
③初始化活动对象,即加入形参、函数声明、变量声明
④将活动对象压入f作用域链顶端
fContext = { AO:{ arguments:{ length:0 } }, Scope:[AO,checkscopeContext.AO,globalContext.VO], this.undefined }
8.f函数执行,沿这作用域链查找scope值并返回
9.f函数执行完毕,f函数上下文从执行上下文栈中弹出
ECStack = [ checkscopeContext, globalContext ];
10.checkscope函数执行完毕,checkscope执行上下文从执行上下文栈中弹出
ECStack = [ globalContext ];
第二段代码就留给大家去尝试模拟它的执行过程
在下一篇《深入--闭包》中也会提及这段代码的执行过程