eval的作用域链直接继承调用者执行上下文的词法环境,不创建新作用域;其var/function声明会注入调用者vo/ao,但不改变作用域链结构,严格模式下行为受限。

eval 执行上下文的作用域链不是独立新建的,而是**直接继承调用它的那个执行上下文的作用域链**。它不创建新的词法作用域,也不改变原有作用域结构,只是在当前作用域内“临时插入”一段代码并立即执行。
eval 的作用域链来源明确
当 eval 被调用时,它不会像函数调用那样生成一个带新变量对象(AO)和独立 [[Scope]] 的函数执行上下文。它的作用域链完全复用**调用者所在执行上下文的 LexicalEnvironment**(即当前的词法环境),包括其 Environment Record 和 outer 链。
- 如果 eval 在全局环境中被调用,它的作用域链就是全局作用域链(只含全局变量对象)
- 如果 eval 在某个函数内部被调用,它的作用域链就包含该函数的活动对象(AO)+外层所有父级环境,直到全局
- 也就是说:eval 没有自己的“父作用域”,它用的就是你写 eval(...) 这行代码时所处的那个作用域
eval 可以修改当前作用域的变量对象
eval 内部若使用 var 或 function 声明,这些声明会**注入到调用者所在的变量对象中**(VO 或 AO),相当于在当前作用域里动态添加了变量或函数。
- 例如在函数 fn 中执行 eval("var x = 100;"),x 就会成为 fn 的 AO 的一部分,后续可直接访问
- 但 let/const 不会被注入——它们属于词法绑定,eval 无法在块级环境中动态创建真正的块级绑定
- 这种“污染”能力正是 eval 危险的原因:它打破了静态可分析性,让作用域行为在运行时才确定
eval 不影响外层作用域链结构
虽然 eval 能往当前 VO/AO 里加东西,但它**不会延长或重构作用域链本身**。outer 指针仍指向原调用者的外层环境,没有新增一环。
- 作用域链长度、顺序、各环节的变量对象都保持不变
- 标识符查找规则照旧:从当前 AO/VO 开始 → 逐级 outer 查找 → 到全局结束
- eval 里引用的变量,解析路径和它外面同一位置写的代码完全一致
与函数执行上下文的关键区别
函数调用会创建全新执行上下文,拥有自己的 AO 和独立 [[Scope]] 属性(固化了定义时的外层链);而 eval 没有 [[Scope]] 属性,它共享调用时刻的 LexicalEnvironment 引用。
- 函数作用域是“封闭且快照式”的(定义时决定)
- eval 作用域是“开放且实时式”的(调用时决定,且可写入)
- 这也是为什么严格模式下 eval 无法访问外部变量声明(如通过 with 或 arguments 修改),且其内部变量自动变为局部,不再污染外层











