执行上下文和执行栈
执行上下文(Execution Context
):当前JS
代码被解析和执行时所在环境的抽象概念。当前代码的执行环境,会形成一个作用域。JavaScript
中的运行环境包括三种:
- 全局环境:
JavaScript
代码运行起来会首先进入该环境; - 函数环境:当函数被调用执行时,进入当前函数中执行代码;
eval
(不建议使用,可忽略)
JS 程序中,会产生多个执行上下文,JS 引擎会以函数调用栈(call stack)的方式来处理,栈底永远是全局上下文,栈顶是当前正在执行的上下文。
代码执行过程中,遇到以上三种情况,都会生成一个执行上下文,放入栈中,处于栈顶的上下文执行完毕后,自动出栈,
例子
1 | var color = 'blue'; |
全局上下文入栈;
执行到
changeColor()
,创建当前函数的执行上下文;执行
changeColor
中的可执行代码,遇到swapColors()
,创建swapColors
执行上下文;swapColors
函数执行完成后,swapColors EC
出栈;- 继续执行
changeColor
函数,执行完成后,changeColor EC
出栈,只剩下全局执行上下文。 - 全局上下文在浏览器窗口关闭后出栈。
注意:函数中,遇到return能直接终止可执行代码的执行,因此会直接将当前上下文弹出栈。
生命周期:创建阶段、执行阶段、回收阶段
创建阶段(函数创建,但未执行)
- 创建变量对象:首先初始化函数的参数 arguments,提升函数声明和变量声明
- 创建作用域链
- 确定 this 指向
函数内部执行时,会形成新的私有作用域,然后依次执行
- 如果有形参,先给形参赋值
- 进行私有作用域的预解释,函数声明优先级比变量声明高,但可以重新赋值,
- 私有作用域中的代码从上到下执行
每次调用函数创建一个新的执行上下文,JS 引擎创建了执行栈来管理执行上下文,执行栈是一个存储函数调用的栈结构,遵循先进后出的原则。
多个函数执行过程:
- JS 执行在单线程上,所有的代码都是排队执行
- 首先创建全局执行上下文,压入执行栈的底部
- 函数执行时就创建新的执行上下文,压入执行栈的底部。
- 函数执行完,该函数执行上下文出栈,等待垃圾回收
- 浏览器的 JS 执行引擎总是访问栈顶执行上下文
- 全局执行上下文只有唯一一个,它在浏览器关闭时出栈。