eval() 和 new Function() 是一回事吗?

IT技术 javascript function optimization eval
2021-01-29 13:23:59

这两个函数在幕后做同样的事情吗?(在单语句函数中)

var evaluate = function(string) {
    return eval('(' + string + ')');
}

var func = function(string) {
    return (new Function( 'return (' + string + ')' )());
}

console.log(evaluate('2 + 1'));
console.log(func('2 + 1'));
6个回答

不,它们一样。

  • eval() 将字符串计算为当前执行范围内的 JavaScript 表达式,并且可以访问局部变量。
  • new Function()将存储在字符串中的 JavaScript 代码解析为函数对象,然后可以调用该函数对象。它无法访问局部变量,因为代码在单独的范围内运行。

考虑这个代码:

function test1() {
    var a = 11;
    eval('(a = 22)');
    alert(a);            // alerts 22
}

如果new Function('return (a = 22);')()使用,局部变量a将保留其值。尽管如此,Douglas Crockford 等一些 JavaScript 程序员认为,除非绝对必要否则不应使用两者,并且对不可信数据进行评估/使用构造函数是不安全和不明智的。Function

@Juan:Crockford 的观点是 eval 经常被误用(取决于您的观点),因此应将其排除在“最佳实践”JavaScript 之外。但是,我确实同意,当第一次正确验证输入时,它对于 JSON 或算术表达式解析等用途很有用。甚至 Crockford 在他的 JSON 库 json2.js 中也使用了它。
2021-03-12 13:23:59
@GeorgeMauer:我想你的意思是eval('(function(){'+code+'})'),它会返回一个函数对象。根据 MDN,“使用 Function 构造函数创建的函数不会为其创建上下文创建闭包;它们总是在窗口上下文中运行(除非函数体以“use strict”; 语句开头,在这种情况下上下文是未定义的) .”
2021-03-24 13:23:59
“不应该被使用”是一个如此宽泛的声明。怎么样,当任何输入超出您的控制时,永远不应该使用。话虽如此,我从来不需要使用它,除了解析 JSON。但是我在这里回答了一些似乎是有效用途的问题,它涉及允许管理员生成最终用户可以使用的模板功能之类的问题。在这种情况下,输入是由管理员生成的,因此可以接受
2021-03-26 13:23:59
那么这是否意味着它与一个全新的执行上下文new Function(code)相同eval('(function(){'+code+'})()')或者是一个全新的执行上下文?
2021-04-09 13:23:59

new Function创建一个可以重用的函数。eval只执行给定的字符串并返回最后一条语句的结果。当您试图创建一个使用 Function 来模拟 eval 的包装函数时,您的问题被误导了。

他们在幕后共享一些代码是真的吗?是的,很有可能。完全一样的代码?不,当然。

为了好玩,这是我自己使用 eval 创建函数的不完美实现。希望它能揭示一些不同之处!

function makeFunction() {
  var params = [];
  for (var i = 0; i < arguments.length -  1; i++) {
    params.push(arguments[i]);
  }
  var code = arguments[arguments.length -  1];


 // Creates the anonymous function to be returned
 // The following line doesn't work in IE
 // return eval('(function (' + params.join(',')+ '){' + code + '})');
 // This does though
 return eval('[function (' + params.join(',')+ '){' + code + '}][0]');
}

this 和 new Function 的最大区别在于 Function 没有词法作用域。所以它不能访问闭包变量,而我的可以。

为什么不使用arguments.slice()代替 for 循环?或者,如果 arguments 不是真正的数组,则[].slice.call(arguments, 1).
2021-04-03 13:23:59

不。

在您的更新中,调用evaluatefunc产生相同的结果。但是,他们绝对不是“在幕后做同样的事情”。func函数创建一个新函数,然后立即执行它,而该evaluate函数只是当场执行代码。

从原来的问题:

var evaluate = function(string) {
    return eval(string);
}
var func = function(string) {
    return (new Function( 'return (' + string + ')' )());
}

这些会给你非常不同的结果:

evaluate('0) + (4');
func('0) + (4');
好吧,你根据他的实现捏造了你的例子。如果他执行评估,return eval('(' + string + ')');那么他们将产生相同的结果。
2021-03-23 13:23:59
@Juan 我没想到,但是是的。编辑了问题
2021-03-25 13:23:59
在任何情况下,除了最例外的情况外,两者都是不好的做法。
2021-04-06 13:23:59

只想指出这里示例中使用的一些语法及其含义:

 var func = function(string) {
     return (new Function( 'return (' + string + ')' )());
 }

请注意,Function(...)() 末尾有“()”。此语法将导致 func 执行新函数并返回字符串而不是返回字符串的函数,但如果您使用以下内容:

 var func = function(string) {
     return (new Function( 'return (' + string + ')' ));
 }

现在 func 将返回一个返回字符串的函数。

如果你的意思是,它会产生相同的结果,那么是的……但只是 eval(也就是“评估这个 JavaScript 字符串”)会简单得多。

编辑下面:

这就像在说……这两个数学问题是一样的吗:

1 + 1

1 + 1 + 1 - 1 + 1 - 1 * 1 / 1

我确定他们都在某个时候解析(评估)字符串,但是当您调用函数时Function对象可能会将字符串存储在私有成员变量中eval
2021-03-12 13:23:59
他们都将解析字符串(在您的代码示例中)。不知道“重新解析”是什么意思。
2021-03-23 13:23:59
他们都重新解析字符串吗?
2021-03-31 13:23:59