mirror of
https://github.com/pengzhanbo/vuepress-theme-plume.git
synced 2026-04-23 10:58:13 +08:00
139 lines
3.6 KiB
Markdown
139 lines
3.6 KiB
Markdown
---
|
||
title: JavaScript进阶(三)— 执行上下文栈
|
||
createTime: 2020/02/11 11:53:33
|
||
author: pengzhanbo
|
||
permalink: /article/6snk1b6c/
|
||
---
|
||
|
||
关于 执行上下文,请点击查看[这篇文章](/article/d12xkizf/)。
|
||
|
||
## 执行上下文栈
|
||
|
||
`JavaScript` 引擎 创建了 执行上下文栈 来存储并管理 代码执行时创建的所有 执行上下文。
|
||
|
||
执行上下文栈(Execution context stack,ECS) 是一个种拥有 LIFO(后进先出) 的栈。
|
||
|
||
我们使用一个数组 模拟 执行上下文栈:
|
||
|
||
```js
|
||
const ECSStack = []
|
||
```
|
||
|
||
当 `JavaScript` 执行时,首先遇到的是 全局代码,初始化时,会首先向 执行上下文栈中压入 全局执行上下文
|
||
(global execution context)。它只有在整个程序结束时,才会被清空,所以在程序结束前, `ECSStack` 底部
|
||
都会有一个 `globalExecutionContext`
|
||
|
||
```js
|
||
const ECSStack = [
|
||
globalExecutionContext
|
||
]
|
||
```
|
||
|
||
当 `JavaScript` 开始执行以下代码时:
|
||
``` js
|
||
function foo() {
|
||
console.log('foo')
|
||
}
|
||
function bar() {
|
||
foo()
|
||
}
|
||
function run() {
|
||
bar()
|
||
}
|
||
|
||
run()
|
||
```
|
||
在这段代码中,`JavaScript` 进行以下处理:
|
||
``` ts
|
||
// 伪代码:
|
||
|
||
// run(), 创建 函数执行上下文,并压入 执行上下文栈
|
||
ECSStack.push(functionExecutionContext<run>)
|
||
|
||
// run() 中发现需要执行 bar(), 继续创建 函数执行上下文,并压入执行上下文栈
|
||
ECSStack.push(functionExecutionContext<bar>)
|
||
|
||
// bar() 中发现需要执行 foo(), 继续创建 函数执行上下文,并压入执行上下文栈
|
||
ECSStack.push(functionExecutionContext<foo>)
|
||
|
||
/** 此时, ECSStack 的结构,如下:
|
||
* [
|
||
* globalExecutionContext,
|
||
* functionExecutionContext<run>,
|
||
* functionExecutionContext<bar>,
|
||
* functionExecutionContext<foo>
|
||
* ]
|
||
*/
|
||
|
||
// 当 foo() 执行完毕,从执行上下文栈中移除 functionExecutionContext<foo>
|
||
ECSStack.pop()
|
||
|
||
// 当 bar() 执行完毕,从执行上下文栈中移除 functionExecutionContext<bar>
|
||
ECSStack.pop()
|
||
|
||
// 当 run() 执行完毕,从执行上下文栈中移除 functionExecutionContext<run>
|
||
ECSStack.pop()
|
||
|
||
// 在程序未结束时, ECSStack 底部永远有一个 globalExecutionContext
|
||
```
|
||
|
||
再看下一个例子:
|
||
|
||
```js
|
||
var scope = "global scope";
|
||
function checkScope(){
|
||
var scope = "local scope";
|
||
function f(){
|
||
return scope;
|
||
}
|
||
return f();
|
||
}
|
||
checkScope();
|
||
```
|
||
|
||
```js
|
||
var scope = "global scope";
|
||
function checkScope(){
|
||
var scope = "local scope";
|
||
function f(){
|
||
return scope;
|
||
}
|
||
return f;
|
||
}
|
||
checkScope()();
|
||
```
|
||
|
||
这两段代码,虽然在执行结果是一样的,都是输出 `local scope`, 但是在 执行上下文栈 中的变化不同。
|
||
|
||
第一段代码, 在 执行上下文栈,模拟处理如下:
|
||
|
||
```ts
|
||
// 执行checkScope()
|
||
ECSStack.push(functionExecutionContext<checkScope>)
|
||
// 在checkScope执行阶段中执行 f()
|
||
ECSStack.push(functionExecutionContext<f>)
|
||
|
||
ECSStack.pop()
|
||
ECSStack.pop()
|
||
```
|
||
|
||
第二段代码, 在执行上下文栈,模拟处理如下:
|
||
|
||
```ts
|
||
// 执行checkScope()
|
||
ECSStack.push(functionExecutionContext<checkScope>)
|
||
ECSStack.pop()
|
||
// 在checkScope 完成后,再执行 f()
|
||
ECSStack.push(functionExecutionContext<f>)
|
||
ECSStack.pop()
|
||
```
|
||
|
||
可以看出, 函数执行的时机不同,虽然最终结果一致,但是在 执行上下文栈 中的过程是不同的。
|
||
|
||
## 总结
|
||
|
||
1. 执行上下文栈,是用于存储和管理所有执行上下文。
|
||
2. 在程序没有结束前,执行栈中永远有一个全局执行上下文。
|
||
3. 函数执行时,会创建一个新的函数执行上下文,并按顺序压入到执行栈中。
|
||
4. 函数执行完成后,对应的函数执行上下文会从执行栈中移除。
|