JS基础之执行上下文和执行栈
学习之前,我要提出一个自己的思想观点:技术知识点的提出,都是为了解决问题。所以不妨先在心中设置一些问题:
“它是什么,它用来解决什么问题,它是如何解决的”
执行顺序
首先,看一道经典的面试题。
foo(); // foo2
function foo() {
console.log('foo1');
}
foo(); // foo2
function foo() {
console.log('foo2');
}
foo(); // foo2
这里面的答案是发生了函数提升。由此可见,Javascript引擎并非是一行一行顺序分析和执行程序的,而是在执行时,就已经知道了foo函数的存在。也就是说,JS在进行时,先做出来预处理,之后再根据预处理的内容处理执行。
那么JS是怎么预处理的?又在执行的过程中按照怎样的流程呢?
执行环境
执行环境(execution context),英文直译是执行上下文。执行环境定义了变量,或者函数有权访问的数据。执行环境中有一个变量对象(VO),环境中所有变量和函数都保存在这个对象中。
执行环境既是一个名词也是一个动词。名词是指它是代码执行的基础环境,当一段 JavaScript 代码在运行的时候,它实际上是运行在执行上下文中。动词是指,在遇到可执行代码时进行的预处理,这些预处理便是执行环境。
可执行代码段有三种:全局代码,函数代码,eval代码
执行环境栈
执行环境通过执行环境栈(execution context stack)来管理。当一个函数执行时,函数的执行环境就会被推入一个环境栈中,而在函数执行结束后,环境也随之被弹出。执行流正是由这个机制控制着。
我们用Stack表示环境栈,环境栈中总会有一个全局执行环境。
var Stack = [
globalContext //全局环境
];
下面举一个例子,演示环境栈的控制过程。
function foo1() {
console.log('foo');
}
function foo2() {
foo1()
}
function foo3() {
foo2();
}
foo3();
环境栈的变化过程:
执行foo3() =>
Stack = [globalContext,foo3Context];
执行foo2() =>
Stack = [globalContext,foo3Context,foo2Context];
执行foo1() =>
Stack = [globalContext,foo3Context,foo2Context,foo1Context];
foo1结束 =>
Stack = [globalContext,foo3Context,foo2Context];
foo2结束 =>
Stack = [globalContext,foo3Context];
foo1结束 =>
Stack = [globalContext];
小结
JS在分析执行时,先做出来预处理,之后再根据预处理的内容处理执行。
执行环境(Execution context)是一种预处理,当函数执行时,便会创建对应的执行环境。执行栈(execution context stack)管理着执行环境,采用先进后出的原则对执行环境进行调度。
这一机制用以控制ECMAScript程序中的执行流程。