eval会“欺骗词法作用域”,即在运行时动态修改静态确定的作用域链:非严格模式下var/function声明污染当前作用域,严格模式下作用域隔离但仍可读写外层变量,间接调用则退化至全局作用域,导致性能下降、调试困难与安全风险。

eval 会直接在调用它的词法作用域内“插入”并执行代码,相当于把字符串内容当作写死在那一行的源码来处理。这会让原本静态、编译期就确定的作用域链,在运行时被动态改写——也就是所谓“欺骗词法作用域”。
非严格模式下:声明会污染当前作用域
在非严格模式中,eval 执行的 var 或 function 声明,会真实地添加到它所处的函数或全局作用域里:
- 比如在函数内部调用
eval("var b = 3"),就会在该函数作用域中创建变量b,遮蔽外层同名变量 -
let和const不会泄漏到外层,但会在 eval 内部新建块级作用域,行为更复杂且不可预测 - 赋值语句如
eval("a = 10")会直接修改外层已存在的a(如果可访问)
严格模式下:作用域被隔离,但仍有风险
开启 "use strict" 后,eval 获得自己的独立词法环境:
-
eval("let x = 5; function f() {}")中的x和f不会出现在外部作用域 - 但 eval 仍能读取和修改外层的变量(只要没被同名声明遮蔽),比如
eval("a = 20")依然生效 - 无法通过 eval 新增外层变量,但也不能完全阻止副作用
间接调用 eval:退化到全局作用域
一旦脱离“直接调用”形式(即不是以标识符 eval 开头),比如:
const e = eval; e("x = 1")window.eval("y = 2")(0, eval)("z = 3")
这些都会让代码在全局作用域执行,var 声明变成全局变量,let/const 仍不泄漏,但赋值操作可能污染全局。
为什么说这是“破坏”而不是“扩展”
词法作用域本应是静态、可分析、可优化的。eval 的介入使引擎无法在编译阶段确认变量归属:
- V8 等引擎会禁用内联缓存和 JIT 优化,性能下降明显
- 调试器难以追踪变量来源,堆栈信息混乱
- 静态检查工具(如 ESLint)无法可靠判断作用域边界
- 安全上无法隔离恶意脚本,容易引发 XSS 或原型污染


















