如何在严格模式下替换`with`语句

lam*_*345 -3 javascript with-statement strict-mode ecmascript-6

此代码运行最佳并且易于理解:

function evalInScope(js, contextAsScope) {
    //# Return the results of the in-line anonymous function we .call with the passed context
    return function() {
        with(this) {
            return eval(js);
        };
    }.call(contextAsScope);
}
evalInScope("a + b", {a: 1, b: 2}); // 3 obviously, but fails in strict mode!
Run Code Online (Sandbox Code Playgroud)

然而,“聪明”的大脑决定删除该with声明,而不进行适当的替换。

问题:如何让它在自动处于严格模式的 ES6 中再次工作?

Ber*_*rgi 5

不要使用eval,而是创建一个new Function。它不会继承词法严格模式 - 更好的是,它不会继承所有函数范围和模块范围的变量:

"use strict";

function evalInScope(js, contextAsScope) {
  return new Function(`with (this) { return (${js}); }`).call(contextAsScope);
}

console.log(evalInScope("a + b", { a: 1, b: 2 })); // 3
Run Code Online (Sandbox Code Playgroud)

此外,您不会得到eval使用的奇怪的“(最后)语句结果”返回值,但可以将js代码限制为表达式或return在代码本身中包含语句。


或者,如果您实际上并不需要使用with复杂的语句,而只是想让一组动态常量变量可供evaled 代码使用,则只需动态生成这些常量的代码即可。这甚至允许eval代码处于严格模式:

"use strict";

function evalInScope(js, contextAsScope) {
  return new Function(
    `"use strict";
    const {${Object.keys(contextAsScope).join(', ')}} = this;
    return (${js});`
  ).call(contextAsScope);
}

console.log(evalInScope("a + b", { a: 1, b: 2 })); // 3
Run Code Online (Sandbox Code Playgroud)

或者如果代码this本身不使用关键字,也许也可以

"use strict";

function evalInScope(js, contextAsScope) {
  return new Function(
    '{' + Object.keys(contextAsScope).join(', ') + '}',
    `return (${js});`
  )(contextAsScope);
}

console.log(evalInScope("a + b", { a: 1, b: 2 })); // 3
Run Code Online (Sandbox Code Playgroud)