动态生成代码的 eval 与 Function

by: gpt4

eval()new Function()都可以用于动态执行 JavaScript 代码,不过它们之间存在一些关键的差异。

作用域

<u>eval()</u>在当前的词法作用域中执行代码,这意味着在使用 <u>eval()</u> 执行的代码可以访问、修改甚至声明当前作用域内的变量。而 <u>new Function()</u> 创建的函数总是在全局作用域中创建和执行,无法访问局部作用域的变量。

1
2
3
4
5
6
7
var x = 10;
eval("x++"); // 可以访问并修改 x
console.log(x); // 输出 11

var y = 10;
new Function("y++")(); // 这里的 y 是新函数作用域内的,不影响外部的 y
console.log(y); // 输出 10,因为全局的 y 没有被改变

参数

new Function() 可以接收一个或多个字符串参数,最后一个参数是函数体,前面的参数都被视为新函数的参数。这为动态生成具有特定参数的函数提供了便利。**使用 Function 创建动态模块,可让 commonjs 模块中加载 ESM,**。eval() 只接受一个参数,即要执行的代码字符串。

1
2
3
4
5
6
7
8
9
var add = new Function("a", "b", "return a + b");
console.log(add(1, 2)); // 输出 3

// commonjs模块中加载ESM, 使用Function创建动态模块
const importDynamic = new Function("modulePath", "return import(modulePath)");
const { ChatGPTAPI } = await importDynamic("chatgpt");

// 这样直接使用 import 会报错,因为编译是就会把 import编译为 require。导致最后不是一个动态模块
const { ChatGPTAPI } = await import("chatgpt");

性能

由于 eval() 可以访问局部作用域,JavaScript 引擎无法在编译时确定 eval() 会做什么,因此可能无法进行某些优化,这可能导致 eval()new Function()执行得更慢。

安全性

两者都可以执行字符串形式的代码,这都存在潜在的安全风险,尤其是当执行的代码来自不可信的来源(如用户输入)时。然而,由于 new Function()不会访问到局部作用域,相比之下,它的安全风险要小一些。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!