什么是 JavaScript 中的执行上下文与作用域链?
解释 JavaScript 执行上下文和作用域链的概念及其关系。
在 JavaScript 中,执行上下文和作用域链是关键运行机制:
- 执行上下文(Execution Context)
- 定义:执行上下文表示 JavaScript 代码运行时的一组环境和状态信息。每次函数或全局代码开始执行时,引擎会创建一个新上下文,如全局上下文、函数上下文或 eval 上下文,用于存储变量和操作。
- 组成:
- 变量对象(Variable Object, VO)或活动对象(Activation Object, AO):存储上下文中的变量、函数声明和参数参数。
- 作用域链(Scope Chain):指定变量查找的顺序。
- this 值:指定当前执行环境的对象(依据调用方式动态绑定)。
- 上下文创建与堆栈管理:引擎使用“执行堆栈(Execution Stack 或 Call Stack)”管理上下文,遵守后进先出(LIFO):
- 初始化后全局上下文入栈(一直存在至脚本结束)。
- 函数调用时新上下文入栈。
- 函数退出时上下文出栈销毁。整个过程不显式发生在 eval(避免使用,常被认为不良实践)。
- 作用域链(Scope Chain)
- 定义:作用域链本质是一个列表顺序地连接所有相关活动/变量对象,规定变量可引用范围,通过词法作用域(即定义时的父作用域而非调用时的)预先安排机制。
- 构成与查找机制:
- 每个函数在定义时创建
[[scope]]
内部不可更改属性记录上级所有变量对象。 - 函数执行初始时动态构建正式链端顺序:从内部(最顶端 AOn/O)起连接外部各级父上下文链,最终链至全局,如“先查找本函数属性 AO,再上层 FO/AO 层层访问直到全局变量对象”。
function a(){ function b(){ console.log(x); //查找路径:查找 AO b -> AO a -> VO global } b(); } a();
这种向下迭代访问路径保证了词法作用域的稳定性。
- 每个函数在定义时创建
- 两者关系的关键要点
- 函数执行上下文内部定义时,其词法级链已经基于定义作用域安排锁定作用域链路径,此不可动态改动属性。
- 全局上下文定义默认无父作用域,唯一唯一上下文。
- 函数上下文创建机制包括 AO 生成(包含参数、var声明、函数等)、此绑定安排操作和 scope_chain 的初始化过程。 以上机制能清晰解读闭包行为及错误查找,此对理解高级编程非常有益。