Function构造函数的合法使用

时间:2010-06-11 20:42:18

标签: javascript function-constructor

正如反复说的那样,使用Function constructor(参见ECMAScript Language Specification,5 th 版本,§15.3.2.1)被认为是不好的做法:

new Function ([arg1[, arg2[, … argN]],] functionBody)

(其中所有参数都是包含参数名称的字符串,最后一个(或唯一)字符串包含函数体)。

总结一下,据说the Opera team

解释说它很慢
  

每次[...] Function   在字符串上调用构造函数   代表源代码,脚本   发动机必须启动机械   将源代码转换为可执行文件   码。这通常是昂贵的   表现 - 轻松一百次   比简单的功能更昂贵   例如,打电话。 (Mark'Tarquin'Wilton-Jones)

虽然不是 不好,但根据MDC上的this post(我没有使用当前版本的Firefox自行测试)。

Crockford adds

  

他指的是公约   语言让人很难   正确表达一个函数体   串。在字符串形式,早期   错误检查无法完成。 [...]并且   因为每个都浪费在记忆上   功能需要自己独立   实施

另一个不同之处在于

  

函数定义的函数   构造函数不继承任何范围   除全球范围外(全部范围)   函数继承)。 (MDC

除此之外,当您使用动态内容创建new Function时,您必须注意避免注入恶意代码。

那说,T.J。克劳德在an answer中说

  

[t]这里几乎没有任何需要   相似的新功能(...),   或者,除了一些先进的   边缘情况。

所以,现在我想知道:这些“先进边缘案例”是什么? 是否合法使用了Function构造函数?

7 个答案:

答案 0 :(得分:19)

NWMatcher - 由Diego Perini创建的Javascript CSS选择器和匹配器 - 使用Function构造函数(1234等等)创建(“编译”)选择器匹配器的高效版本。

benchmark(我刚刚在Chrome 5上运行)说明了一切:

alt text

注意NWMatcher和Sizzle之间的区别,这是一个非常相似的选择器引擎,只有没有函数编译:)

另一方面,ECMAScript 5 在调用Function时不会抛出任何错误。无论是严格的还是“标准的”模式。但是,严格模式对标识符的存在几乎没有限制,例如“eval”和“arguments”:

  • 您不能使用以下名称声明变量/函数/参数:

    function eval() { }
    var eval = { };
    function f(eval) { } 
    var o = { set f(eval){ } };
    
  • 您无法分配此类标识符:

    eval = { };
    

另请注意,在严格模式下,eval语义与ES3略有不同。严格模式代码无法在调用它的环境中实例化变量或函数:

 eval(' "use strict"; var x = 1; ');
 typeof x; // "undefined"

答案 1 :(得分:9)

当JSON解析器对象不可用时,jQuery使用它来解析JSON字符串。似乎对我来说是合法的:))

        // Try to use the native JSON parser first
        return window.JSON && window.JSON.parse ?
            window.JSON.parse( data ) :
            (new Function("return " + data))();

答案 2 :(得分:7)

我在我正在开发的一个网络应用程序中使用new Function()构造函数作为内联JS解释器:

function interpret(s) {
  //eval(s); <-- even worse practice
  try {
      var f = new Function(s);
      f();
    }
  catch (err) {
      //graceful error handling in the case of malformed code
  }
}

当我通过AJAX( iframe)获取内容时,我会interpret()继续readyStateChange == 3它。这非常有效。

修改:这是一个明确的案例研究,显示new Function()明显快于eval()。即你不应该(很少?)使用eval代替new Function()

http://polyfx.com/stuff/bsort.html&lt; - 1000次迭代版本,可能会导致浏览器崩溃

http://polyfx.com/stuff/bsort10.html&lt; - 较短的版本

平均值,平均值<强> 8倍慢于new Function()

答案 3 :(得分:7)

John Resig使用Function构造函数创建用asp语法编写的客户端模板的“编译”版本。 http://ejohn.org/blog/javascript-micro-templating/

答案 4 :(得分:3)

这与我的其他答案不同。

我稍后使用了Function构造函数来创建重复调用的自定义字符串格式化程序。创建函数(我认为是你所讨论的性能问题)的开销远远超过定制函数的改进性能,这些函数是在运行时创建的,专门用于处理特定的格式字符串,因此不需要评估大量无关的案例 - 或解析格式字符串。我想,这有点像编写正则表达式。

答案 5 :(得分:3)

我唯一合法的用途是我写这篇文章:

Function.prototype.New = (function () {
  var fs = [];
  return function () {
    var f = fs [arguments.length];
    if (f) {
      return f.apply (this, arguments);
    }
    var argStrs = [];
    for (var i = 0; i < arguments.length; ++i) {
      argStrs.push ("a[" + i + "]");
    }
    f = new Function ("var a=arguments;return new this(" + argStrs.join () + ");");
    if (arguments.length < 100) {
      fs [arguments.length] = f;
    }
    return f.apply (this, arguments);
  };
}) ();

该代码允许您在“使用”Function.prototype.apply关键字时使用new

示例:

function Foo (x, y, z) {
  this.x = x;
  this.y = y;
  this.z = z;
  this.otherArgs = Array.prototype.slice.call (arguments, 3);
}

var foo = Function.prototype.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New.apply (Foo, [1, 2, 3, 4, 5, 6, 7]);
// /*equiv*/ var foo = Foo.New (1, 2, 3, 4, 5, 6, 7);
var bool = true
  && foo.x == 1
  && foo.y == 2
  && foo.z == 3
  && foo.otherArgs.length == 4
  && foo.otherArgs [0] == 4
  && foo.otherArgs [1] == 5
  && foo.otherArgs [2] == 6
  && foo.otherArgs [3] == 7
  ;

alert (bool);

答案 6 :(得分:2)

您可能希望多次执行一串代码。使用Function构造函数意味着您只需编译一次。

您可能希望将参数传递给代码,例如,如果您要填充事件,则可以检索事件属性并构造期望事件参数的函数。

您可以将两者结合起来并在一个位置编译它并在另一个位置执行它,并且仍然设法在代码字符串所需的变量中传递参数。