本文介绍在 ES6+ 严格模式下替代已废弃的 with 语句的三种可靠方案,重点使用 new Function() 动态构造执行上下文,兼顾安全性、兼容性与可维护性。
本文介绍在 es6+ 严格模式下替代已废弃的 `with` 语句的三种可靠方案,重点使用 `new function()` 动态构造执行上下文,兼顾安全性、兼容性与可维护性。
在 JavaScript 严格模式(ES5 起默认启用,ES6 模块及顶层脚本自动严格)中,with 语句被完全禁用——不仅语法报错,且因其动态作用域带来的性能退化、调试困难与安全隐患,ECMAScript 标准明确将其移除。但某些场景(如轻量模板求值、配置表达式解析、沙箱化脚本执行)仍需将对象属性“注入”为局部变量供表达式使用。此时,直接调用 eval() 会继承外层严格模式而失败;而 with 又不可用。解决方案的核心思路是:脱离当前作用域链,通过 new Function() 创建独立执行环境,并显式构造所需变量绑定。
✅ 推荐方案一:new Function + with(仅限非严格子环境)
虽然全局或模块作用域处于严格模式,但 new Function() 创建的函数不继承调用者所在作用域的严格模式状态(即其内部默认非严格),因此可在其中合法使用 with:
"use strict";
function evalInScope(js, contextAsScope) {
// 注意:此处的 with 在 new Function 内部执行,不受外部 "use strict" 影响
return new Function(`with (this) { return (${js}); }`).call(contextAsScope);
}
console.log(evalInScope("a + b", { a: 1, b: 2 })); // → 3
⚠️ 注意事项:
- 此方法虽简洁,但 with 本身仍存在变量查找歧义、压缩工具误判等风险,不建议用于生产环境的高可靠性场景;
- js 必须是纯表达式(如 "a + b"),若含语句(如 if),需手动包裹 return 或确保末尾为表达式。
✅ 推荐方案二:解构赋值 + 显式常量声明(推荐用于严格模式友好场景)
更现代、更安全的方式是避免 with,转为静态生成变量声明。利用 Object.keys() 动态提取上下文属性名,通过解构语法注入常量:
"use strict";
function evalInScope(js, contextAsScope) {
const keys = Object.keys(contextAsScope);
const paramStr = keys.length ? `{${keys.join(', ')}}` : '';
const body = `return (${js});`;
return new Function(
`"use strict";\nconst ${paramStr} = this;\n${body}`
).call(contextAsScope);
}
console.log(evalInScope("a + b", { a: 1, b: 2 })); // → 3
console.log(evalInScope("a * 10", { a: 5 })); // → 50
✅ 优势:
- 完全运行于严格模式下(内部显式声明 "use strict");
- 变量作用域清晰、无隐式查找,利于静态分析与压缩;
- 避免 with 的所有语义陷阱。
✅ 进阶方案三:参数化传入(适用于无 this 依赖的简单场景)
若待执行代码不依赖 this,且上下文属性均为基本类型,可进一步优化为函数参数形式,彻底消除 this 绑定开销:
"use strict";
function evalInScope(js, contextAsScope) {
const keys = Object.keys(contextAsScope);
// 构造形参列表:a, b, c...
const paramList = keys.join(', ');
// 构造函数体:return (a + b);
const body = `return (${js});`;
return new Function(paramList, body)(...Object.values(contextAsScope));
}
console.log(evalInScope("a + b", { a: 1, b: 2 })); // → 3
✅ 优势:
- 执行上下文完全隔离,无 this 干扰;
- 参数顺序与值严格对应,行为可预测;
- 性能略优(避免 .call() 与 this 查找)。
⚠️ 重要安全提醒
无论采用哪种方案,动态执行字符串代码(eval / new Function)均存在严重安全风险:
- ❌ 切勿执行不可信输入(如用户提交的表达式);
- ✅ 如必须动态求值,请结合白名单校验、AST 解析(如 acorn)或专用表达式引擎(如 math.js, expr-eval)替代;
- ✅ 生产环境优先考虑预编译、模板函数或配置驱动逻辑,而非运行时代码拼接。
综上,在严格模式下替代 with,new Function 是技术上最直接的桥梁。但真正的工程最佳实践是:用显式、静态、可验证的方式重构需求,而非模拟已被淘汰的动态作用域机制。










