eval不创建新作用域,直接复用调用位置的词法环境,导致var/function声明污染外层作用域,let/const在严格模式下仅限临时块级作用域,无法突破闭包或模块私有边界,且调试与静态分析完全失效。

eval 执行上下文不创建新作用域,它直接复用调用位置的词法环境,因此变量声明会“注入”到当前作用域中,而非隔离运行——这是它影响变量与作用域的核心机制。
var 和 function 声明会污染外层作用域
在非严格模式下,eval 内部的 var x = 1 或 function foo() {} 会被当作写在调用位置的代码一样处理,直接挂载到当前函数的活动对象(AO)或全局对象上。
- 函数内执行
eval("var a = 42"),后续可直接访问a,就像手动写了var a = 42 -
eval("function bar() {}")总是被提升到所在函数作用域顶层,即使在 if 块里执行也一样 - 重复调用
eval("var cache = cache || []")可能导致意外覆盖或多次初始化
let/const 行为受严格模式和引擎版本约束
ES2015+ 中,eval("let y = 100") 在严格模式下合法,但 y 仅存在于 eval 所在的临时块级作用域内,不会泄漏到外层;非严格模式下则报错或行为未定义。
- 这不同于 var/function:let/const 不注入 AO,而是创建临时绑定,执行完即销毁
- 不能通过 eval 动态创建闭包外不可见的私有变量(如模块内的 #field 或 const 常量)
- 拼错变量名(如
eval("console.log(xxx)"))仍会抛 ReferenceError,和普通代码一致
作用域链不变,但变量对象被动态修改
eval 不新增作用域链环节,它的查找路径与外层代码完全相同:从当前 AO 开始 → 沿 outer 链逐级向上 → 到全局结束。但它允许在运行时往当前 AO 里写入新条目。
- 调用者作用域的变量对象(VO/AO)被实际修改,不是“模拟”或“快照”
- 箭头函数中调用 eval,仍沿用外层函数的 this 和词法环境,不会获得新 this
- 无法绕过 const 冻结、Symbol 私有属性或模块封装边界
调试与工具链完全失效
因为字符串内容只能在运行时确定,静态分析工具无法验证其合法性,引擎也无法优化或映射源码位置。
- 堆栈追踪显示
eval at …,Source Map 断点失效 - TypeScript 不检查 eval 内部类型,ESLint 默认禁用相关规则
- 代码压缩器(如 Terser)通常跳过混淆,甚至拒绝打包含 eval 的模块











