eval复用当前执行上下文,可直接访问和修改外层变量;new function创建全新函数上下文,作用域链仅含全局作用域,无法访问外层局部变量,必须显式传参。

eval 和 new Function() 都能动态执行字符串代码,但它们的执行上下文机制完全不同——这不是“写法不同”,而是运行时环境的根本差异。
eval 复用当前上下文,没有独立栈帧
eval 不创建新执行上下文,它直接在调用它的那个函数(或全局)环境中运行,共享全部环境信息:
- 变量对象(VO)就是外层函数的 VO,var 声明会提升到外层作用域顶部
- 作用域链完全一致,可自由读写外层的局部变量、形参、const/let 声明(非严格模式下甚至能修改 const)
- this 和 arguments 直接继承外层,不重新绑定
- 执行完毕不留痕迹,不参与执行栈弹出流程
new Function 创建全新函数上下文
new Function("a", "b", "return a + b") 生成的是一个真正的函数对象,每次调用都会压入新的函数执行上下文:
- 作用域链只包含全局(或模块)作用域,无法访问外层函数的任何局部变量
- 必须显式传参才能使用外部数据,比如 new Function("username", "password", ruleString)
- 拥有独立的 this 绑定逻辑(默认为全局对象,严格模式下为 undefined)和 arguments 对象
- 可形成闭包,但仅限于它自身定义时捕获的外部变量(如通过闭包传入的配置)
安全与调试表现差异明显
因为执行上下文模型不同,两者在实际工程中行为迥异:
- eval 能直接污染外层变量,容易引发意外覆盖或原型篡改,且无法被静态分析工具识别风险
- new Function 更可控:参数明确、作用域隔离、可被压缩工具处理,也更容易做沙箱封装
- 调试时,eval 的代码不会出现在调用栈中(或只显示为 anonymous),而 new Function 会显示为独立函数名(若指定)
- 严格模式下,eval 内部仍继承外层 this;new Function 则按标准规则绑定 this
什么时候该选哪个?
基本没有“该选 eval”的现代场景。除非你在写 JS 引擎测试用例或极特殊 polyfill:
- 需要访问当前作用域变量 → 用闭包包装逻辑,别用 eval
- 要执行用户输入表达式 → new Function + 参数白名单 + try/catch 封装
- 配置化系统需动态计算 → 把变量提前解构为参数传入 new Function
- 想绕过 CSP 策略 → eval 被多数策略禁止,new Function 同样受限,应改用 AST 解析等替代方案











