【问题标题】:Are eval() and new Function() the same thing?eval() 和 new Function() 是一回事吗?
【发布时间】: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

标签: javascript function optimization eval


【解决方案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 做同样的事情(如果应用在问题的上下文中)
    猜你喜欢
    • 2015-07-30
    • 1970-01-01
    • 2019-11-03
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多