这个系列是我读冴羽老师博客的感悟,
加入了个人的解读和练习题的解答
我们知道在js中有变量提升,
所以js引擎在解析代码的时候不是一行一行去执行的,而是一段一段去分析
(暂且以函数花括号来划分段)
实际环境中的函数可能是一层套一层执行的,加上函数有各自的静态作用域
javascript引擎创建了执行上下文栈(Execution context stack,ECS)来管理这些情况
由于函数的执行是有顺序的,执行上下文栈是先进后出的栈结构
我们这里用数组来模拟它
首先执行全局代码,此时在ECStack中压入一个 globalContext
1
2
3
|
ECStack = [
globalContext
]
|
然后我们执行下面的实例代码
1
2
3
4
5
6
7
8
9
10
|
function a() {
console.log("run a")
b()
}
function b() {
console.log("run b")
}
a()
|
首先执行a函数,在ECStack中压入函数a的执行上下文,
1
2
3
4
|
ECStack = [
<a> functionContext,
globalContext
]
|
发现执行函数a中,需要执行b函数(此时a还没执行完,没有出栈),在ECStack中压入函数b的执行上下文
1
2
3
4
5
|
ECStack = [
<b> functionContext,
<a> functionContext,
globalContext
]
|
函数b执行完后,函数b的执行上下文出栈,ECStack.pop()
然后函数a也执行完了,继续 ECStack.pop()
就是这么一个执行栈
另一个例子:
代码A
1
2
3
4
5
6
7
8
9
|
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
|
代码B
1
2
3
4
5
6
7
8
9
|
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();
|
首先代码A和代码B 都会打印 localscope,具体原因在上一篇作用域中有解释
但不同的是A和B的执行上下文的顺序不同
伪代码是这样的
1
2
3
4
5
|
//代码A
ECStack.push(<checkscope> functionContext)
ECStack.push(<f> functionContext)
ECStack.pop() //f 执行结束
ECStack.pop() //checkscope 执行结束
|
1
2
3
4
5
|
//代码B
ECStack.push(<checkscope> functionContext)
ECStack.pop() //checkcope 执行结束
ECStack.push(<f> functionContext)
ECStack.pop() //f 执行结束
|