执行上下文栈
JavaScript代码执行顺序是同步的
var foo = function(){
console.log('foo1')
}
foo(); // foo1
var foo = function(){
console.log('foo2')
}
foo(); // f002
再看看下面的代码有什么不同
function foo(){
console.log('foo1');
}
foo(); // foo2
function foo(){
console.log('foo2');
}
foo(); // foo2
看出什么不同了吗?JavaScript引擎执行代码是一段一段的,不是一行一行执行的。
当一段执行完毕后,进行下一段的'准备工作'。
'准备工作' 也叫做 预编译 分为 变量提升 函数声明提升。
可执行代码
这里就讲讲什么是可执行代码:
可执行代码就是指将目标代码连接后形成的代码,简单来说就是机器能直接执行的代码。
那可执行代码分几种类型呢?
分为三种:全局代码、函数代码、eval代码
- 全局代码:作为JavaScript Program 处理的源代码文本。
- 函数代码:作为FunctionBody 被解析的的源代码文本。
- eval代码:提供给eval内置函数的源代码文本。
这里就不细说可执行代码的深层知识,喜欢可以关注,后续会更新发布有关JavaScript的相关知识干货。
上面讲到'准备工作',到底'准备工作'是什么时候进行的呢?
举个例子,当代码执行的时候,就会进行准备工作,这里的'准备工作',专业点来说,就是叫做"执行上下文(Execution Context)"
执行上下文栈
每次代码执行都会创建一个执行上下文,那么我们如何管理呢?
JavaScript引擎有一个"执行上下文栈(Execution context stack , ECS)"来帮助你管理。
现在我么模拟一下执行上下文栈,这里定义执行上下文栈是一个数组。
ECStack = [];+
JavaScript引擎开始解析代码的时候,最先遇到的是全局代码,所以初始化 执行上下文栈中添加一个名字叫globalContext的全局执行上下文,而且只有程序结束运行,ECStackcai'hui被清空,所以ECStack结束前,ECStack最顶部都会有一个globalContext。
ECStack = [
globalContext
];
现在看看这段代码:
function foo3(){
console.log('foo3');
}
function foo2(){
foo3();
}
function foo1(){
foo2();
}
foo1();
当执行了一个函数,就会创建一个执行上下文,并且添加到执行上下文栈中,当函数执行完毕,就会将该函数的执行上下文从执行上下文栈中删除,按照这样的工作原理,我们看看JavaScript引擎怎么处理上面这段代码。
// 执行foo1(),创建foo1()的执行上下文
ECStack.push(foo1<functionContext>);
// ECStack = [globalContext,foo1<functionContext>];
// foo1()中执行了foo2(),创建foo2()的执行上下文
ECStack.push(foo2<functionContext>);
// ECStack = [globalContext,foo1<functionContext>,foo2<functionContext>];
// foo2()中执行了foo3(),创建foo3()的执行上下文
ECStack.push(foo3<functionContext>);
// ECStack = [globalContext,foo1<functionContext>,foo2<functionContext>,foo3<functionContext>];
// foo3()执行结束,删除foo3()的执行上下文
ECStack.pop();
// ECStack = [globalContext,foo1<functionContext>,foo2<functionContext>];
// foo2()执行结束,删除foo2()的执行上下文
ECStack.pop();
// ECStack = [globalContext,foo1<functionContext>];
// foo1()执行结束,删除foo1()的执行上下文
ECStack.pop();
// ECStack = [globalContext];
// 关闭程序,清空ECStack
ECStack.pop();
// ECStack = [];
执行上下文
- 作用域链 scope
- 变量对象 GO AO (预编译)
- this 执行上下文一旦删除,以上三个内容都会被删除
最后小例子
var scope = 'global scope';
function checkscope(){
var scope = 'local scope';
function f(){
return scope;
}
return f();
}
checksope();
var scope = 'global scope';
function checkscope(){
var scope = 'local scope';
function f(){
return scope;
}
return f;
}
checksope()();
两段代码执行结果一样,到底两段代码有什么不同呢?
大家看完这篇文章应该都能想到,是执行上下文栈的变化不一样
模拟一下两段的执行上下文栈的变化
ECStack.push(checkscope<functionContext>);
ECStack.push(f<functionContext>);
ECStack.pop();
ECStack.pop();
ECStack.push(checkscope<functionContext>);
ECStack.pop();
ECStack.push(f<functionContext>);
ECStack.pop();
今天的分享就到此为止啦!喜欢可以关注点赞走一波,谢谢大家!