eval 默认共享调用者作用域,会在当前作用域链顶层注入变量和函数,导致污染;let/const 仍参与同作用域声明检查,无法完全避免;更安全的替代方案包括 function 构造器、json.parse、沙箱环境或 ast 白名单执行。

JavaScript 中 eval 执行动态代码时,默认会污染当前作用域,这是它最危险的特性之一。它的作用域行为不是“新建一个隔离作用域”,而是直接在**调用时所在的作用域链顶层注入变量和函数**——也就是说,eval 里声明的 var、function 会泄漏到外层,而 let/const 虽受块级作用域保护,但若在全局或函数顶部使用,仍可能覆盖同名绑定。
eval 默认共享调用者作用域
eval 没有自己独立的词法作用域,它沿用执行时的 LexicalEnvironment(词法环境)。这意味着:
- 在函数内调用
eval("var x = 1"),x会成为该函数的局部变量(等价于写在函数体里) - 在全局作用域调用
eval("var y = 2"),y会挂到全局对象上(如window.y) - 即使用了
"use strict",eval内部的var也不会变成块级绑定,只是禁止隐式创建全局变量(但仍可污染当前函数作用域)
let/const 不能完全避免污染
有人以为用 let 就安全了,其实不然:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
eval("let z = 3")在函数中执行,z仍是该函数作用域内的块级绑定,后续代码可访问 - 如果多次调用
eval声明同名let,会抛出Identifier 'z' has already been declared—— 这说明它确实在参与当前作用域的声明检查 - 真正“隔离”的只有
Function构造器(见下文),eval从不隔离
更安全的替代方案
除非绝对必要,应避免 eval。可行的替代方式包括:
-
用
Function构造器:它创建的是新函数,作用域链只包含全局,不会污染调用者作用域。例如:const fn = new Function('a', 'b', 'return a + b');,其内部无法读写外层变量(除非显式传入) -
JSON.parse 处理纯数据:如果目标只是解析字符串为对象,永远优先用
JSON.parse,而非eval -
沙箱环境(如 iframe 或 VM 模块):Node.js 可用内置
vm模块创建受限上下文;浏览器中可借助iframe.contentWindow创建隔离全局环境(注意 CSP 限制) - AST 解析 + 白名单执行:对表达式做语法分析,仅允许安全操作(如加减乘除、属性访问),拒绝函数调用、赋值、声明等高风险结构
严格模式下 eval 的变化
"use strict" 对 eval 的影响有限但重要:
- 禁止
eval内部创建隐式全局变量(即eval("x = 1")不再自动挂到全局,而是报错ReferenceError) - 但
eval("var x = 1")依然有效,并在当前函数作用域声明x -
eval内部无法通过arguments.callee或caller访问调用栈,提升安全性
不复杂但容易忽略:eval 的作用域本质是“透明透传”,它不建墙,只开门。真正隔离靠的是换房间(Function),而不是锁门(strict mode)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










