【问题标题】:$.each() vs for() loop - and performance$.each() 与 for() 循环 - 和性能
【发布时间】:2012-08-06 22:00:03
【问题描述】:

这些主要只是我一直想知道的一些事情,也许有人可以给我更多的见解,我也会分享我到目前为止所注意到的!

我一直想知道的第一件事......有什么好的或理由使用的区别:

$('element').each(function (i, el) { });

-- 对比--

$.each($('element'), function (i, el) { });

查看 jQuery 文档,我看不出其中的任何一个押韵或原因(也许您知道一个实例或其他事情可以做的事情。

但更重要的是我关心的是速度这里

// As opposed to $.each() looping through a jQuery object
// -- 8x faster 
for (var i = 0, $('.whatever').length; i < len; i++) {
    $('.whatever')[i] // do stuff
}

如果您查看此 jsFiddle DEMO here,您会发现速度差异基本上与它们中的任何一个相同,但更重要的是我觉得我应该始终 正在使用for() 循环...

我只是进行单元测试(循环遍历 5 个不同的场景函数中的每一个,50,000 次),简单地遍历一堆列表项,并设置一个 data-newAttr,没什么特别的。


问题 :: 我想我最大的问题是,为什么不总是在遍历对象时使用 for 循环?使用 $.each() 有什么意义吗?即使在遍历 jQuery 对象时,你是否总是使用 for() 循环?

jsFiddle DEMO here

Function type:                  Execution Time:
_testArea.each() + $(this)               1947   <-- using $(this) slows it down tremendously
$.each()         + $(this)               1940
_testArea.each() + el(plain JS)           458   <-- using the Element speeds things up
$.each()         + el(plain JS)           452
for() loop       + plainJS[0] iteration   236   <-- over 8x faster

只有我的 2 美分。 :)

【问题讨论】:

  • 正如乔·阿姆斯特朗在回答 Erlang 邮件列表上的一个类似问题时所写的那样,“只写你能写的最漂亮的程序。”让性能问题来找你。你真的会处理迭代 50,000 次的页面吗?如果是,那么一定要优化。
  • for 循环遍历 jQuery DOM 元素会是什么样子?
  • 在 jsperf.com 上自己测试一下
  • 总是,Javascript 函数会比 Jquery 函数更快,因为 javascript 是本机的,但我认为使用 each 而不是 for 的意义在于,它使用框架使代码更快,以及优势
  • .each() 方法迭代 jQuery 对象。 $.each() 静态方法可以迭代各种类型的对象,如普通对象、数组和类数组对象。这就是区别。

标签: javascript jquery


【解决方案1】:

.each() 允许您做的一件事是for 循环无法做到的,那就是链接

$('.rows').each(function(i, el) {
    // do something with ALL the rows
}).filter('.even').each(function(i, el) {
    // do something with the even rows
});

I played around with your JSFiddle 了解在您必须遍历原始匹配元素集的子集的情况下,链接如何影响性能。

结果并没有那么出乎意料,尽管我认为end() 的开销在这里被夸大了,因为它结合了少量元素和许多循环。除此之外:普通的 JS 循环仍然稍微快一些,但这是否与 .each()(和链接)增加的可读性相称是值得商榷的。

【讨论】:

  • 哇!谢谢,没想到这么上链,这本身绝对是一大利好!在纯 JS 中要做的代码要多得多,一旦你发生了一堆 if/else 事情来完成同样的事情,ms 的好处就几乎不存在了。
  • 表现不佳!我会在外部 each() 内部进行过滤,因为 each().filter() 会处理相同的数组两次,它不太方便但性能更高。如果您期望大量元素,那么我将完全放弃使用 each() 迭代,只需查看 jsperf.com/function-call-overhead-test 关于函数调用开销
【解决方案2】:

当我访问您的链接时,我得到了两个数字:

$.each() + el(plain JS) 401
for() loop + plainJS[0] iteration   377

如果差异那么小,则选择可读性最强的那个,但是,如果您对时间的要求非常高,那么您可能只需要选择最终最快的那个。

我建议您编写程序以使用三种不同的方法,即上述两种方法,然后使用较新版本的 javascript 中的 foreach,对于那些不支持它的浏览器,您可以将其添加为原型。

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/forEach

您知道自己的要求是什么,以及您的程序会做什么,所以只需编写自己的测试并确保它满足您将支持的浏览器的要求。

对于您的第一个问题,我会选择$('element').each,因为它更容易阅读,但这只是我的看法。

【讨论】:

  • 虽然对于这么小的利润,它可能 不会产生 [rhymes with spam] 一点差异 .. 我只会使用“更清晰一致的版本”(以哪个为准确定是),除非有一个特定现实世界的性能案例表明它太慢了。
  • @pst - 如果你调用它 10000 次,那么小的边距会产生影响,而这个小的差异会让你超出允许的窗口,这就是我要问的,也是真正知道的唯一方法就是用三个版本在各种浏览器上测试,得到一些数字。
  • 谢谢詹姆斯!是的,在我的情况下,这绝对是一个问题,我们需要支持旧版浏览器,但现在我看到 可读性和可链接性 - 明智 - 使用 each() 是有意义的,然后坚持使用纯 JS !区别真的不存在,看来除非我需要它保持一个JS对象,否则我不需要使用$(this)
【解决方案3】:

您使用.each() 所做的一件事是自动本地范围界定(因为您正在为每个对象调用一个匿名函数),这反过来意味着如果您要创建更多的匿名函数/闭包/事件处理程序/无论在每个迭代,你永远不必担心你的处理程序共享一个变量。也就是说,JavaScript 在局部作用域方面的表现与其他语言不同,但因为您可以在任何地方声明变量,所以它有时会欺骗您。

换句话说,这是错误的:

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx]
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
}

只要这些对象中的任何一个在此循环之后调用它们的“someEvent”(请注意这是编造的),警报总是会说出最后分配给 idx 的任何内容,应该是(截至当时调用)someObjectArray.length;

为了确保保存正确的索引,您必须声明一个局部范围,创建一个变量并分配给该变量以供使用。

var idx,el;
for (idx = 0; idx <someObjectArray.length; idx++){
   el = someObjectArray[idx];
   (function(){
       var localidx = idx;
       el.someEventHandler(function(){  
           alert( "this is element " + localidx);
       }); 
   })();
}

如您所见,这简直丑到不行,但它应该可以工作。每个事件处理程序都有自己的 localidx 副本

现在将其与 .each() 进行比较

$(someObjectArray).each(function (idx, el) { 
   el.someEventHandler(function(){  
       alert( "this is element " + idx);
   }); 
});

简单多了,不是吗?

【讨论】:

  • 非常真实!我实际上忘记了一秒钟它已经为你做了这个......我想从中得到的最重要的事情是,如果你想要简单的操作 | get/set type things an easy for() w 纯 JS 确实是要走的路。对于更复杂的过滤和事件处理程序,您几乎需要 each()。有趣...
【解决方案4】:

我在http://jsperf.com/forloops3 前进行了一些简单的性能测试。似乎坚持简单的、旧的for loop(在可能的情况下)是要走的路:)

【讨论】:

    【解决方案5】:

    其实$.each()和$().each()是有很大区别的。

    根据您传递的内容,它们会做些许不同的事情。

    http://api.jquery.com/each/http://api.jquery.com/jquery.each/

    jquery.each 是一个通用迭代器,其中 $().each() 特定于一个 jquery 集合。

    另见:http://jsperf.com/each-vs-each-vs-for-in/9

    【讨论】:

    • 您可以以同样的方式轻松使用两者:$(['someItem', 'anotherItem']).each(function (i, el) { });jsfiddle.net/zzVQD。此外,这并不意味着这个问题值得一票否决,我在其中投入了大量的研究/代码/努力。
    • 虽然这不是这个问题的答案,但它增加了一些知识。
    【解决方案6】:

    jQuery.each 与 for 循环

    jQuery.each 的优点:

    • 非常适合 jQuery 代码(链接和样式)。
    • 不用担心范围(对迭代器和对象的引用将保持不变)。
    • 可以通用(用于各种对象和迭代对象键)。

    for循环的优点:

    • 高性能(用于游戏/动画/大型数据集)。
    • 完全控制迭代器(跳过项目、拼接列表中的项目等)。
    • for 循环将始终有效,因为不依赖于 jQuery。
    • 与大多数其他类似语言的语法相同。

    示例代码

    这是我喜欢如何迭代列表的示例代码。

    var list = ['a', 'b', 'c', 'd', 'e', 'f'];
    

    jQuery.each:

    $.each(list, function(i, v)
    {
        // code...
    });
    

    没有闭包的for循环:

    for(var i=0,v,n=list.length;i<n;i+=1)
    {
        v = list[i];
        // code...
    }
    

    带闭包的for循环:

    for(var i=0,n=list.length;i<n;i+=1)
    {
        (function(i, v)
        {
            // code...
        })(i, list[i]);
    }
    

    注意:我建议你只使用标准的 for 循环,并且只在必要时使用闭包。但是,当您的代码看起来更像 jQuery 而不是 Javascript 时,使用 $.each 可能会更容易。如果出现性能问题,您可以随时查看。

    【讨论】:

      猜你喜欢
      • 2010-09-20
      • 1970-01-01
      • 2015-11-12
      • 1970-01-01
      • 2015-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-18
      相关资源
      最近更新 更多