
本文详解在 ES6+ 严格模式中替代已废弃 with 语句的三种专业方案:使用 new Function 绕过严格模式限制、动态解构注入作用域变量,以及参数化函数构造,兼顾安全性、可读性与兼容性。
本文详解在 es6+ 严格模式中替代已废弃 `with` 语句的三种专业方案:使用 `new function` 绕过严格模式限制、动态解构注入作用域变量,以及参数化函数构造,兼顾安全性、可读性与兼容性。
在 JavaScript 严格模式(ES5.1 起强制启用,ES6 模块默认启用)中,with 语句被完全禁用——不仅因性能问题,更因其破坏作用域链可预测性,导致调试困难、静态分析失效及潜在安全风险。因此,原依赖 with(this) 动态扩展求值作用域的代码(如 evalInScope 工具函数)将直接抛出 SyntaxError。但需求依然存在:需在受控环境中,以给定对象为“词法上下文”执行动态 JavaScript 表达式。以下提供三种生产就绪的替代方案,按推荐度递进说明。
✅ 方案一:new Function + with(兼容性优先,需谨慎)
虽然严格模式禁止 with,但 new Function(...) 创建的函数不继承外层严格模式(ECMAScript 规范明确:Function 构造器生成的函数拥有独立的严格模式上下文)。因此,可将 with 封装在新函数体内,规避语法错误:
"use strict";
function evalInScope(js, contextAsScope) {
// 注意:js 必须是纯表达式,或显式包含 return
const fn = new Function(`with (this) { return (${js}); }`);
return fn.call(contextAsScope);
}
console.log(evalInScope("a + b", { a: 1, b: 2 })); // → 3⚠️ 重要注意事项:
- 此方式仍存在 with 的固有缺陷(如屏蔽原型属性、难以调试),且 new Function 与 eval 同样受 CSP(Content Security Policy)限制;
- js 字符串必须确保为合法表达式,否则运行时报错;建议配合白名单校验或 AST 预检。
✅ 方案二:动态解构 + 严格模式内联(推荐:安全 & 清晰)
更现代、更安全的做法是放弃 with,转而显式注入变量。利用 Object.keys() 动态生成解构赋值语句,再在严格模式下执行:
"use strict";
function evalInScope(js, contextAsScope) {
const keys = Object.keys(contextAsScope);
const destructuring = keys.length ? `const {${keys.join(', ')}} = this;` : '';
const fn = new Function(
`"use strict";\n${destructuring}\nreturn (${js});`
);
return fn.call(contextAsScope);
}
console.log(evalInScope("a + b", { a: 1, b: 2 })); // → 3
console.log(evalInScope("a * c", { a: 2, c: 4 })); // → 8(c 未定义?不!此处 c 是解构变量)✅ 优势:
- 完全运行于严格模式,无兼容性隐患;
- 变量名显式声明,避免 with 的作用域污染和意外覆盖;
- 支持 IDE 智能提示与静态检查(若 js 为模板字符串且键名已知)。
✅ 方案三:参数化函数构造(最佳实践:零作用域污染)
若动态代码不依赖 this 或复杂嵌套,最健壮的方式是将上下文作为参数传入,彻底消除 this 和作用域操作:
"use strict";
function evalInScope(js, contextAsScope) {
const keys = Object.keys(contextAsScope);
// 构造形参列表:如 `(a, b) => ...`
const params = keys.join(', ');
const fn = new Function(params, `return (${js});`);
return fn(...Object.values(contextAsScope));
}
console.log(evalInScope("a + b", { a: 1, b: 2 })); // → 3
console.log(evalInScope("x - y", { x: 10, y: 3 })); // → 7? 核心优势:
- 零副作用:不操作 this,不修改作用域链;
- 类型友好:参数顺序与值一一对应,便于 TypeScript 类型推导(可进一步封装为泛型函数);
- CSP 友好度更高:虽仍用 new Function,但无字符串拼接 this 引用,降低 XSS 风险面。
总结与选型建议
| 方案 | 安全性 | 可维护性 | 适用场景 |
|---|---|---|---|
| new Function + with | ⚠️ 中(保留 with 缺陷) | ❌ 低(隐式作用域) | 遗留系统快速迁移,短期过渡 |
| 动态解构(const {...} = this) | ✅ 高(严格模式) | ✅ 高(显式变量) | 大多数动态表达式求值需求 |
| 参数化函数((...args) =>) | ✅✅ 最高(无 this/with) | ✅✅ 最佳(函数式风格) | 新项目首选,尤其需类型安全或高可靠性场景 |
最后强调:所有方案均依赖 new Function,它与 eval 共享核心风险——执行不可信字符串即等同于远程代码执行。务必确保 js 参数来源可信,或在服务端进行沙箱化预处理(如使用 vm2 等隔离环境)。切勿将用户输入未经清洗直接传入 —— 安全永远优于便利。

















