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

Posted

技术标签:

【中文标题】eval() 和 new Function() 是一回事吗?【英文标题】:Are eval() and new Function() the same thing? 【发布时间】:2011-06-03 17:54:39 【问题描述】:

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

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'));

【问题讨论】:

实际上这是在 jQuery 1.7.2 第 573 行中使用的。虽然带有“一些安全检查” 为什么在这个讨论中考虑newFunction 隐式实例化 function object。排除new 根本不会更改代码。这是一个 jsfiddle 证明:jsfiddle.net/PcfG8 【参考方案1】:

不,它们相同。

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 程序员认为 neither should be used 除非 absolutely necessary,并且在不受信任的数据上评估/使用 Function 构造函数是不安全和不明智的。

【讨论】:

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

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).【参考方案3】:

没有。

在您的更新中,对 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 + ')');,那么它们将产生相同的结果。 @Juan 我没想到,但是是的。编辑了问题【参考方案4】:

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

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

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

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

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

【讨论】:

【参考方案5】:

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

在下面编辑:

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

1 + 1

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

【讨论】:

他们都重新解析字符串吗? 它们都将解析字符串(在您的代码示例中)。不知道你所说的“重新解析”是什么意思。 我确信它们都会在某个时候解析(评估)字符串,但是当您调用函数时,Function 对象可能会将字符串存储在 eval 的私有成员变量中。 【参考方案6】:

在那个例子中,结果是一样的,是的。两者都执行您传递的表达式。这就是使它们如此危险的原因。

但他们在幕后做不同的事情。涉及new Function() 的幕后花絮从您提供的代码中创建了一个匿名函数,该函数在调用该函数时执行。

在您调用匿名函数之前,您传递给它的 JavaScript 在技术上不会执行。这与eval() 形成对比,后者会立即执行代码,并且不会基于它生成函数。

【讨论】:

你能多解释一下吗?他们不是都在return语句中执行的吗? Function() 是否使用与 eval 不同的堆栈调用级别? Does the Function() one use another stack call level than eval?:我会这么认为,因为eval() 不会根据您的输入创建函数——它只是执行它。 new Function() 创建一个新函数,然后调用它。 @SimpleCoder: Function() 不会向调用堆栈添加任何内容。仅当您调用结果函数时。 eval 做同样的事情(如果应用在问题的上下文中)

以上是关于eval() 和 new Function() 是一回事吗?的主要内容,如果未能解决你的问题,请参考以下文章

eval和new Function的区别

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

javascript JS_new_Function()_ EVAL

Javascript动态执行JS(new Function与eval比较)

超级超级好玩的东西: eval 与new Function的用法

make eval builtin function