正如反复说的那样,使用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构造函数?
答案 0 :(得分:19)
NWMatcher - 由Diego Perini创建的Javascript CSS选择器和匹配器 - 使用Function
构造函数(1,2,3,4等等)创建(“编译”)选择器匹配器的高效版本。
benchmark(我刚刚在Chrome 5上运行)说明了一切:
注意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构造函数意味着您只需编译一次。
您可能希望将参数传递给代码,例如,如果您要填充事件,则可以检索事件属性并构造期望事件参数的函数。
您可以将两者结合起来并在一个位置编译它并在另一个位置执行它,并且仍然设法在代码字符串所需的变量中传递参数。