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 行中使用的。虽然带有“一些安全检查” 为什么在这个讨论中考虑new
? Function
隐式实例化 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】:
没有。
在您的更新中,对 evaluate
和 func
的调用会产生相同的结果。但是,他们绝对不是“在幕后做同样的事情”。 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() 是一回事吗?
javascript JS_new_Function()_ EVAL
Javascript动态执行JS(new Function与eval比较)