Zha*_*ami 28 javascript jslint
我有一些代码在循环中调用匿名函数,类似于这个伪示例:
for (i = 0; i < numCards; i = i + 1) {
card = $('<div>').bind('isPopulated', function (ev) {
var card = $(ev.currentTarget);
....
Run Code Online (Sandbox Code Playgroud)
JSLint报告错误"不要在循环中创建函数".我喜欢保持我的代码JSLint干净.我知道我可以将匿名函数移出循环并将其作为命名函数调用.除此之外,这是我的问题:
Javascript解释器是否真的会为每次迭代创建一个函数实例?或者只有一个函数实例"已编译"并且重复执行相同的代码?也就是说,将函数移出循环的JSLint"建议"实际上是否会影响代码的效率?
T.J*_*der 42
部分取决于您使用的是函数表达式还是函数声明.它们是不同的东西,它们发生在不同的时间,它们对周围的范围产生不同的影响.让我们从区别开始吧.
函数表达式是一种function生产,其中您将结果用作右手值 - 例如,您将结果分配给变量或属性,或将其作为参数传递给函数,等等.这些都是函数表达式:
setTimeout(function() { ... }, 1000);
var f = function() { ... };
var named = function bar() { ... };
Run Code Online (Sandbox Code Playgroud)
(不要使用最后一个 - 这称为命名函数表达式 - 实现有bug,尤其是IE.)
相反,这是一个函数声明:
function bar() { ... }
Run Code Online (Sandbox Code Playgroud)
它是独立的,你没有将结果用作右手值.
它们之间的两个主要区别:
评估函数表达式在程序流中遇到的位置.当控件进入包含范围(例如,包含函数或全局范围)时,将评估声明.
函数的名称(如果有的话)在函数声明的包含范围中定义.它不适用于函数表达式(禁止浏览器错误).
你的匿名函数是函数表达式,因此禁止解释器进行优化(可以自由地进行),它们将在每个循环中重新创建.因此,如果您认为实施将进行优化,那么您的使用就可以了,但将其分解为命名函数还有其他好处,而且 - 重要的是 - 不会花费任何成本.另外,看卡萨布兰卡的回答了为什么解释可能不是一个音符能够优化再造出在每次迭代的功能,这取决于它如何深刻检查你的代码.
更大的问题是如果你在循环中使用函数声明,条件的主体等:
function foo() {
for (i = 0; i < limit; ++i) {
function bar() { ... } // <== Don't do this
bar();
}
}
Run Code Online (Sandbox Code Playgroud)
从技术上讲,仔细阅读规范的语法表明这样做是无效的,尽管实际上几乎没有实现强制执行.什么implemenations 做是不同的,它是最好远离它.
对于我的钱,最好的办法是使用单个函数声明,如下所示:
function foo() {
for (i = 0; i < limit; ++i) {
bar();
}
function bar() {
/* ...do something, possibly using 'i'... */
}
}
Run Code Online (Sandbox Code Playgroud)
你得到相同的结果,实现不可能在每个循环上创建一个新函数,你可以获得具有名称的函数的好处,并且你不会丢失任何东西.
cas*_*nca 24
Javascript解释器是否真的会为每次迭代创建一个函数实例?
它必须因为它不知道函数对象是否会在别处修改.请记住,函数是标准JavaScript对象,因此它们可以具有与任何其他对象类似的属性.当你这样做:
card = $('<div>').bind('isPopulated', function (ev) { ... })
Run Code Online (Sandbox Code Playgroud)
如你所知,bind可以修改对象,例如:
function bind(str, fn) {
fn.foo = str;
}
Run Code Online (Sandbox Code Playgroud)
显然,如果在所有迭代中共享函数对象,这将导致错误的行为.