如何在严格模式下安全替代 with 语句

本文详解在 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 })); // → 3console.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 })); // → 3console.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 等隔离环境)。切勿将用户输入未经清洗直接传入 —— 安全永远优于便利。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。