【问题标题】:functions within loops, why are they considered an 'error'循环中的函数,为什么它们被认为是“错误”
【发布时间】:2014-02-25 22:24:56
【问题描述】:

对于在循环中声明的复杂函数,我可以理解为什么我不想这样做,但为什么它会被认为是糟糕的 javascript?

当然,我们可以命名函数并将其置于循环之外,但会因为一些简单的事情(没有异步)而扰乱流程。

例如,下面是一个循环内的简单内联函数声明(JSHINT/LINT 抱怨,为什么这被认为是不可以?

for (var i = 0, len=arr.length; i < len; ++i) {

     dosomething(arr[i], function(returnvalue) {
         console.log(returnvalue);
     });

};

【问题讨论】:

标签: javascript


【解决方案1】:

这是您不希望这样做的原因之一。该函数引用相同的变量。

http://jsfiddle.net/RCzyF/

var a = [];

for(var i=0; i<10; i++) {
    a.push(function () {
      return i; 
    });
}

h = "";
for(var j=0; j<10; j++) {
 h += "" + a[j]();   
}

alert(h);

人们可能希望看到0123456789,但它会将10 附加到h 10 次。当一个函数可能会改变其他函数的内容时,它会使代码非常难以理解。

这里有一个更复杂的例子,事情是如何出错的。

var a = [];

for(var i=0; i<10; i++) {
    a.push(function () {
      return i++; 
    });
}

h = "";
for(var j=0; j<10; j++) {
 h += "" + a[j]();   
}

alert(h);

创建函数时,它们指向相同的词法范围。当函数执行时,它们会改变函数内部的值,并且数组中的每个函数仍然指向相同的值。当变量被修改但您没有直接修改它时,这可能会导致非常难以调试的错误。

这也是来自 jslint 本身的真正答案:http://jslinterrors.com/dont-make-functions-within-a-loop/

【讨论】:

  • 看我的回答。我证明了“匿名函数创建一次”是错误的
  • 感谢 Loic,这是对问题的额外奖励,表明循环范围变量不是新创建的。非常酷,值得一看!
  • 谢谢 Loic,我将其标记为正确,就像在我的示例中一样,我将 'i' 传递给内联函数,您的答案显示了潜在的问题,并且,来自新链接(谢谢为此),它将范围问题解释为警告的真正原因。我看到在许多情况下@Dystroy 也是正确的,但必须遵守问题中的示例,这(连同 Oleg Grenrus 的解释)显示了最清楚的原因。感谢大家!王牌学习。
【解决方案2】:

在每次迭代中创建一个函数是无用的繁重。

大多数时候,在客户端 JavaScript 中,性能并不重要,也没有问题,但最好养成并保持良好的习惯,而不是稍后再优化代码(只要不妨碍可读性)。

这是您在每次迭代中创建一个新函数的证明:

var old;
function compare(_, a){
  if (old) console.log('equal ?', old==a);
  else old = a;
}
for (var i=0; i<2; i++){
  compare(i, function(i) { return i*i }); 
}

它记录'equal' ? false

testable jsbin

【讨论】:

  • 感谢 Dystroy,有道理。
  • 据我记得它不会多次创建该函数。匿名函数只创建一次,并在作用域中引用相同的变量。
  • @LoïcFaure-Lacroix 你可能对我的编辑感兴趣。
  • 即使它被多次创建,真正的问题是它引用了相同的变量,并且你的i 没有被复制到作用域中,因此稍后执行的函数可能具有奇怪的值。
  • 确实在每次迭代中都会创建新的函数对象,但是我确信在所有当前的 javascript 实现中,函数的代码部分都是共享的。所以是的,它会给垃圾收集器带来匿名函数对象的负担,但它并不“更重”。我做了一个小基准测试,结果并不奇怪:jsperf.com/function-in-the-loop
猜你喜欢
  • 1970-01-01
  • 2021-06-21
相关资源
最近更新 更多