面向急切程序员的 JavaScript(ES2022 版)
请支持本书:购买捐赠
(广告,请勿屏蔽。)

26 动态评估代码:eval()new Function()(高级)



在本章中,我们将介绍两种动态评估代码的方法:eval()new Function()

26.1 eval()

给定一个包含 JavaScript 代码的字符串 streval(str) 会评估该代码并返回结果。

> eval('2 ** 4')
16

调用 eval() 有两种方式:

“不通过函数调用”指的是“任何看起来不像 eval(···) 的东西”。

以下代码说明了区别:

globalThis.myVariable = 'global';
function func() {
  const myVariable = 'local';
  
  // Direct eval
  assert.equal(eval('myVariable'), 'local');
  
  // Indirect eval
  assert.equal(eval.call(undefined, 'myVariable'), 'global');
}

在全局上下文中评估代码更安全,因为代码可以访问的内部结构更少。

26.2 new Function()

new Function() 创建一个函数对象,并按如下方式调用:

const func = new Function('«param_1»', ···, '«param_n»', '«func_body»');

上一条语句等价于下一条语句。请注意,«param_1» 等不再位于字符串字面量中。

const func = function («param_1», ···, «param_n») {
  «func_body»
};

在下一个示例中,我们创建了两次相同的函数,第一次通过 new Function(),第二次通过函数表达式。

const times1 = new Function('a', 'b', 'return a * b');
const times2 = function (a, b) { return a * b };

  new Function() 创建非严格模式函数

默认情况下,通过 new Function() 创建的函数是 松散模式。如果我们希望函数体处于严格模式,则必须 手动开启

26.3 建议

尽可能避免动态评估代码。

很多时候,JavaScript 本身就足够动态,因此您不需要 eval() 或类似的东西。在以下示例中,我们使用 eval()(A 行)所做的事情在没有它的情况下也可以实现(B 行)。

const obj = {a: 1, b: 2};
const propKey = 'b';

assert.equal(eval('obj.' + propKey), 2); // (A)
assert.equal(obj[propKey], 2); // (B)

如果您必须动态评估代码: