在JavaScript中循环使用一组元素的最佳方法是什么?

时间:2008-10-01 11:57:49

标签: javascript arrays loops elements

在过去,对于我目前的大多数项目,我倾向于使用这样的for循环:

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

我听说使用“反向循环”循环更快但我无法确认这一点:

var elements = document.getElementsByTagName('div'), 
    length = elements.length;

while(length--) {
    doSomething(elements[length]);
}

在循环使用JavaScript中的元素或任何数组时,最佳做法是什么?

14 个答案:

答案 0 :(得分:54)

这是我经常使用的一个很好的循环形式。您可以从for语句创建迭代变量,而不需要检查length属性,这在迭代NodeList时特别昂贵。但是,你必须小心,如果数组中的任何值可能是“虚假”,就无法使用它。在实践中,我只在迭代不包含空值的对象数组(如NodeList)时使用它。但我喜欢它的语法糖。

var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];

for (var i=0, item; item = list[i]; i++) {
  // Look no need to do list[i] in the body of the loop
  console.log("Looping: index ", i, "item" + item);
}

请注意,这也可以用于向后循环(只要您的列表没有['-1']属性)

var list = [{a:1,b:2}, {a:3,b:5}, {a:8,b:2}, {a:4,b:1}, {a:0,b:8}];

for (var i = list.length - 1, item; item = list[i]; i--) {
  console.log("Looping: index ", i, "item", item);
}

ES6更新

for...of为您提供名称,但不提供自ES6

以来可用的索引
for (let item of list) {
    console.log("Looping: index ", "Sorry!!!", "item" + item);
}

答案 1 :(得分:26)

请注意,在某些情况下,需要以相反的顺序循环(但之后您也可以使用i--)。

例如,有人想使用新的getElementsByClassName函数来循环给定类的元素并更改此类。他发现两个元素中只有一个被改变了(在FF3中) 那是因为该函数返回一个实时NodeList,从而反映了Dom树中的变化。以相反的顺序走列表避免了这个问题。

var menus = document.getElementsByClassName("style2");
for (var i = menus.length - 1; i >= 0; i--)
{
  menus[i].className = "style1";
}

在增加索引进度时,当我们询问索引1时,FF检查Dom并使用style2跳过第一个项目,这是原始Dom的第2个,因此它返回第3个初始项目!

答案 2 :(得分:9)

我喜欢这样做:

 
var menu = document.getElementsByTagName('div');
for (var i = 0; menu[i]; i++) {
     ...
}

每次迭代都没有调用数组的长度。

答案 3 :(得分:7)

冒着被大吼大叫的风险,我会得到像jqueryprototype这样的javascript助手库,它们将逻辑封装在漂亮的方法中 - 两者都有.each方法/迭代器来做 - 他们都努力使其跨浏览器兼容

编辑:这个答案发布于2008年。今天存在更好的结构。这个特殊情况可以用.forEach来解决。

答案 4 :(得分:6)

我认为使用第一种形式可能是要走的路,因为它可能是迄今为止已知宇宙中最常见的循环结构,并且因为我不相信反向循环可以在现实中节省你的任何时间(仍然在做)增量/减量和每次迭代的比较)。

其他人可识别和可读的代码绝对是件好事。

答案 5 :(得分:6)

我之前遇到过与document.getElementsByClassName()类似的问题。我当时并不知道节点列表是什么。

var elements = document.getElementsByTagName('div');
for (var i=0; i<elements.length; i++) {
    doSomething(elements[i]);
}

我的问题是我希望元素是一个数组,但它不是。 nodelist Document.getElementsByTagName()返回是可迭代的,但你不能在其上调用array.prototype方法。

可以填充一个带有nodelist元素的数组,如下所示:

var myElements = [];
for (var i=0; i<myNodeList.length; i++) {                               
    var element = myNodeList[i];
    myElements.push(element);
};

之后,您可以随意调用.innerHTML或.style或类似元素的内容。

答案 6 :(得分:4)

我也建议使用简单的方式(KISS! - )

- 但是可以找到一些优化,即不要多次测试数组的长度:

var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
    doSomething(elements[i]);
}

答案 7 :(得分:4)

另见我对Andrew Hedges测试的评论......

我只是尝试运行一个测试来比较一个简单的迭代,我引入的优化和反向do / while,其中数组中的元素在每个循环中进行测试。

唉,毫不奇怪,我测试的三个浏览器的结果非常不同,尽管优化的简单迭代最快! -

测试:

在真实测试之外构建一个包含500,000个元素的数组,每次迭代都会显示特定数组元素的值。

试运行10次。

IE6:

结果:

简单:984,922,937,984,891,907,906,891,906,906

平均值:923.40毫秒。

优化:766,766,844,797,750,750,765,765,766,766

平均值:773.50毫秒。

反向做/同时:3375,1328,1516,1344,1375,1406,1688,1344,1297,1265

平均值:1593.80毫秒。 (注意一个特别尴尬的结果)

Opera 9.52:

结果:

简单:344,343,344,359,343,359,344,359,359,359

平均值:351.30毫秒。

优化:281,297,297,297,297,281,281,297,281,281

平均值:289.00毫秒

反向做/同时:391,407,391,391,500,407,407,406,406,406

平均值:411.20毫秒。

FireFox 3.0.1:

结果:

简单:278,251,259,245,243,242,259,246,247,256

平均值:252.60毫秒。

优化:267,222,223,226,223,230,221,231,224,230

平均值:229.70毫秒。

反向做/同时:414,381,389,383,388,389,381,387,400,379

平均值:389.10毫秒。

答案 8 :(得分:3)

Juan Mendez 提供的循环形式非常有用和实用, 我稍微改了一下,所以现在它也可以使用 - false,null,zero和empty字符串。

var items = [
    true,
    false,
    null,
    0,
    ""
];

for(var i = 0, item; (item = items[i]) !== undefined; i++)
{
    console.log("Index: " + i + "; Value: " + item);
}

答案 9 :(得分:1)

我知道你不想听到这个,但是:我认为最好的做法是在这种情况下最具可读性。只要循环不计数从这里到月球,性能增益就不够了。

答案 10 :(得分:0)

我更喜欢for循环,因为它更具可读性。从长度到0的循环比从0到长度的循环更有效。如你所说,使用反向while循环比foor循环更有效。我没有比较结果页面的链接,但我记得不同浏览器的差异各不相同。对于某些浏览器,反向while循环速度是其两倍。但是,如果你循环“小”数组,它没有任何区别。在您的示例中,元素的长度将为“小”

答案 11 :(得分:0)

我认为你有两种选择。对于诸如jQuery和类似框架之类的dom元素,为您提供了一种很好的迭代方法。第二种方法是for循环。

答案 12 :(得分:-1)

如果元素集是根节点的子节点,我喜欢使用TreeWalker

答案 13 :(得分:-1)

我知道这个问题已经过时了 - 但这是另一个非常简单的解决方案......

var elements = Array.from(document.querySelectorAll("div"));

然后它可以像任何标准数组一样使用。