eval无法真正改变作用域链,仅在非严格模式下直接调用时于当前词法作用域内执行并可能污染该作用域;间接调用或严格模式下均退化为全局执行,且function构造函数才是安全控制动态执行作用域的推荐替代方案。

很多人误以为 eval 可以像函数调用那样创建新作用域或修改作用域链,但实际上它的作用非常有限,且在现代 JavaScript 中几乎失去了这种能力。
eval 不创建新作用域,只复用当前作用域
在非严格模式下,eval 执行的代码会直接在调用它的词法作用域中运行 —— 它共享外层函数的变量、参数和闭包,不会新增作用域层级。也就是说,eval("var x = 1") 声明的变量会成为当前函数的局部变量(类似手写声明)。
- 它不推入新环境记录(Environment Record)到作用域链
- 它访问变量时,查找路径与外层代码完全一致
- 它不能访问外层不可见的私有绑定(比如 let/const 块级绑定仍受块作用域保护)
“间接 eval”彻底脱离当前作用域
当 eval 被赋值给变量、作为参数传递或通过其他方式“间接调用”时(如 const f = eval; f("x = 2")),它会在全局作用域中执行,且无法访问当前函数的局部变量:
- 间接调用等价于在全局作用域执行,只访问全局对象(如
window或globalThis) - 此时
eval的作用域链只有全局环境,完全丢失调用点的闭包信息 - 严格模式下,间接 eval 更安全:它始终在独立的全局作用域中运行,不会污染全局变量(除非显式赋值到 globalThis)
严格模式下 eval 的作用域更受限
在严格模式中,eval 的行为被进一步约束:
- 不能声明变量提升(
var不再提升到函数顶部) -
eval内部声明的let/const/function仅在 eval 内部生效,不影响外层 - 无法通过
eval动态修改外层函数的参数绑定(参数不再可重赋值) - 禁止访问调用栈或尝试绕过作用域规则(如伪造
this或arguments)
替代方案:用函数代替 eval 控制作用域
若目标是“在特定作用域中执行动态代码”,应避免 eval,改用立即执行函数表达式(IIFE)或 Function 构造器:
-
Function构造器创建的函数拥有自己的词法作用域,但只继承全局作用域(不捕获外层闭包) - IIFE 可显式传入所需变量,实现可控的“沙箱式”执行环境
- 现代方案如
vm.Script(Node.js)或Web Workers提供更安全的隔离执行环境
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











