执行上下文:
js得可执行代码,有以下三类:全局代码,函数代码,eval代码。当js 引擎遇到这三种代码时,会开始工作,创建执行上下文。执行上下文得生名周期有俩个阶段:准备阶段和代码执行阶段,在准备阶段,会做三件事,即用arguments创建当前执行上下文得活动对象,确定当前执行上下文得作用域链和绑定当前执行上下文得this属性。
1:作用域链 scope
2: 变量对象 AO GO (预编译)
3:this
执行上下文(Execution context 简称 EC)
js 是单线程得 ,运行在全局EC 每进入一个 function 就做一次入栈操作,然后向栈顶压入一个该属性function 得新得EC,如果function 中又调用了另一个function 则 在执行依次入栈。。。。。依次执行完在依次出栈,回到全局EC 。全局EC一定在栈底,浏览器关闭后出栈。
执行上下文栈:
js代码执行顺序是什么,大部分人都知道同步执行
var foo = function(){
console.log('foo1');
}
foo(); // foo1
var foo = function(){
console.log('foo2');
}
foo() // foo2
看完之后比较下面得代码
function foo(){
console.log('foo1');0
}
foo();// foo2
function foo(){
console.log('foo2');
}
foo() // foo2
js 引擎 执行是一段一段得解析得 ;不是一行一行得解析得 当一段代码执行完毕后 ,会进行一个准备工作,
比如:第一个列子,变量提升,第二个列子:函数声明提升
而这个准备工作就是: 变量提升,和函数提升
现在思考一个问题,写了这么多得函数,去哪里了 怎么管理创建得那么多执行上下文呢?
所以js 引擎创建了执行上下文栈来管理执行上下文
为了模拟执行上下文栈得行为,我们来定义执行上下文栈式一个数组
ECStack = [];+
假设当js 开始要解释执行代码得时候,最先遇到得就是 全局代码,所以初始化得时候首先就会 向下 执行上下文栈 添加一个全局执行上下文,我们用 gobal context 表示它 并且当整个应用程序结束得时候 ECStack 才会被清空 ,所以程序结束之前 ,ecstack 最底部 永远有个 globaltext
// 模拟将全局执行上下文添加到执行上下文栈中
ECStack = [
globalContext
];
现在js 引擎 遇到下面的这段代码:
function foo3() {
console.log('foo3')
}
function foo2() {
foo3();
}
function foo1() {
foo2();
}
foo1();
当执行一个函数的时候,就会创建一个执行上下文,并且添加执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出。 这就是 工作原理。
// 模拟js引擎执行代码
// foo1()
ECStack.push(<foo1> functionContext);
// foo1中竟然调用了foo2,还要创建foo2的执行上下文
ECStack.push(<foo2> functionContext);
// foo2还调用了foo3!创建 foo3执行上下文
ECStack.push(<foo3> functionContext);
// ECStack= [globalContext,foo1<functionCountext>,foo2<functionCountext>,foo3<funcrtionCountext>]
// foo3执行完毕 foo3执行上下文销毁
ECStack.pop();
// ECStack= [globalContext,foo1<functionCountext>,foo2<functionCountext>]
// foo2执行完毕 foo2执行上下文销毁
ECStack.pop();
// ECStack= [globalContext,foo1<functionCountext>]
// foo1执行完毕,foo1执行上下文销毁
ECStack.pop();
// ECStack= [globalContext]
// javascript接着执行下面的代码,但是ECStack底层永远有个globalContext
// 关闭浏览器 关闭应用程序
// ECStack.pop()
// ECStack = []