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

IT技术 javascript arrays loops elements
2021-02-03 03:13:00

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

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

我听说使用“反向 while”循环更快,但我没有真正的方法来确认这一点:

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

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

在 JavaScript 中循环元素或任何数组时,什么被认为是最佳实践?

6个回答

这是我经常使用的一种很好的循环形式。您从 for 语句创建迭代变量,并且不需要检查 length 属性,这在遍历 NodeList 时特别昂贵。但是,您必须小心如果数组中的任何值可能是 "falsy"则不能使用它在实践中,我只在迭代不包含空值的对象数组(如 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 (const item of list) {
    console.log("Looping: index ", "Sorry!!!", "item" + item);
}
@sudopeople 只是为了 100% 准确,当该项目不存在时,它返回undefined这是假的。
2021-03-18 03:13:00
我非常喜欢这个。起初我想知道循环如何退出然后我记得声明的“中间”基本上是一段时间,当评估为假时将退出。为变量分配一个不存在的数组索引 == false!很聪明。
2021-04-03 03:13:00
Drats,没看到这个!对不起骗子!
2021-04-04 03:13:00

请注意,在某些情况下,您需要以相反的顺序循环(但您也可以使用 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 个初始项目!

一个很好的观点,尽管我不建议动态更改 className,因为它会强制浏览器重新计算整个文档的渲染......
2021-03-15 03:13:00
@roenving - 理论上,您可以将整个文档复制到内存中,更改您想要的任何内容,并用新的、修改过的文档替换整个文档。但这要视情况而定。
2021-04-02 03:13:00

我喜欢做:

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

每次迭代都不会调用数组的长度。

只要确保您不要在 null,undefined,false,0,"" 是有效元素的数组上开始使用它!
2021-03-17 03:13:00
一个非常快速的测试(直接在我的编辑器浏览器中)表明,一千次迭代不可能告诉时间,你的方案说 15 毫秒,原始测试每次迭代的长度是 31 毫秒......
2021-04-04 03:13:00

我之前在 document.getElementsByClassName() 中遇到了一个非常相似的问题。我当时不知道节点列表是什么。

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

我的问题是我希望元素是一个数组,但它不是。节点列表 Document.getElementsByTagName() 返回的是可迭代的,但您不能对其调用 array.prototype 方法。

但是,可以使用节点列表元素填充数组,如下所示:

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

之后,您可以随意调用 .innerHTML 或 .style 或数组元素上的其他内容。

冒着被骂的风险,我会得到一个像jquery原型这样的 javascript 帮助库,它们将逻辑封装在很好的方法中 - 都有一个 .each 方法/迭代器来做到这一点 - 他们都努力使其跨浏览器兼容

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

老实说,jQuery 只是为了处理循环?疯狂。
2021-03-15 03:13:00
为什么要使用库来执行简单的任务?-)
2021-03-26 03:13:00
@Tim:实际上我认为我会使用 javascript 创建的网站很少,添加 jquery 会是疯狂的吗?与不相比,使用 jquery 的并发症是什么?
2021-03-29 03:13:00
这个问题写的时候可能还可以。由于大多数浏览器(IE9+)都支持Array.prototype.forEach,它现在已经过时了
2021-03-29 03:13:00
我知道我知道。我只是喜欢包含 jquery 来最小化引入跨浏览器不兼容问题的风险。您不需要在“doSomething”中使用大量代码来可能引入这些错误之一。
2021-03-31 03:13:00