js的执行上下文以及执行上下文栈
可执行代码
js的可执行代码(executable code)有哪些?只有可执行代码会创建执行上下文
- 全局代码
- 函数代码
- eval代码
执行上下文
只有可执行代码会创建执行上下文
当执行到一个函数的时候这里会进行准备工作,
这个准备工作用专业点的话讲就是 执行上下文(execution context)
这里一定是!函数执行的时候才会去创建执行上下文!
对于每一个执行上下文,都有三个重要属性
- 变量对象(Variable object) 俗称VO
- 作用域链(Scope chain)
- this
这些属性可以去对应的文章中看
执行上下文栈
js以执行上下文栈的方式去创建一个执行上下文栈,来进行各个上下文之间的管理
在所有的情况下,执行js的代码,首先遇到的是全局代码这是毋庸置疑的
这个时候相当于这个全局的执行上下文就是在栈底了
首先我们先模拟一下,创建一个栈表示执行上下文栈
ECStack = [];按照上面所说的,执行上下文栈底永远都有一个全局的执行上下文,这里用globalContext表示
ECStack=[ globalContext]按题分析
解释执行上下文栈
function fn3(){ console.log('fn3')}
function fn2(){ console.log('fn2'); fn3();}
function fn1(){ console.log('fn1'); fn2();}
fun1();当执行一个函数的时候,就会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出。
因此以上的代码执行原理是这样的
//fn1()ECStack.push(<fn1> function1Context);// 这时候发现fun1中调用了fn2ECStack.push(<fn2> function2Context);// fn2中又调用了fn3ECStack.puhs(<fn3> function3Context);// 此时的ECStack为// ECStack = [// globalContext// function1Context// function2Context// function3Context// ]
//fn3执行完了ECStack.pop(); // function3Context// fn2执行完了ECStack.pop(); // function3Context// fn1执行完了ECStack.pop(); // function1Context
// javascript接着执行下面的代码,但是ECStack底层永远有个globalContext根据上下文栈以及作用域链以及VO或者AO分析
例如
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: [globalContext.VO], this: globalContext.VO}3.在第2步初始化的过程发现全局的作用域中定义了一个 checkscrope函数,这个函数的作用域链上就会先推入一个全局上下文对象中的Scope
checkscope.[[scope]]=[ globalContext.VO]4.执行 checkscope 函数,创建 checkscope 函数执行上下文,checkscope 函数执行上下文被压入执行上下文栈
ECStack = [ globalContext, checkscopeContext,]5.checkscope函数执行上下文的初始化
- 复制函数的[[scope]]属性创建作用域链,放到checkscopeContext的[[scope]]中
- 用arguments创建活动对象
- 初始化活动对象,加入形参,内部函数声明,变量声明
- 将活动对象压入 checkscope 作用域链顶端,也就是checkscope.VO
- 函数f被声明,保存checkscope的作用域链到fn函数的[[scope]]当中
checkscopeContext = { AO:{ arguments: { length: 0, }, scope: undefined, f: refrence to function f(){} }, Scope: [checkscopeContext.AO, globalContext.VO], this: undefined} 6. 执行函数f,创建f的执行上下文,f函数的执行上下文被压入栈中
ECStack= [ globalContext, checkscopeContext, fnContext]-
f函数执行上下文初始化,和第5步一样
fnContext = {AO = {arguments:{length: 0}},Scope: [fnContext.AO, checkscopeContext.AO, globalContext.VO],this: undefined} -
f函数执行之后,沿着作用域链查找到scope的值,返回scope值
-
f函数执行完,栈中pop出上下文
ECStack.pop()ECStack = [globalContext,checkscopeContext,] -
checkscope函数执行完毕,checkscope执行上下文pop出栈
ECStack.pop()ECStack = [globalContext,]