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

发布于 2024-07-06 15:39:42 字数 451 浏览 4 评论 0原文

在过去和我当前的大多数项目中,我倾向于使用这样的 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 中的元素或任何数组吗?

In the past and with most my current projects I tend to use a for loop like this:

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

I've heard that using a "reverse while" loop is quicker but I have no real way to confirm this:

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

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

What is considered as best practice when it comes to looping though elements in JavaScript, or any array for that matter?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

妞丶爷亲个 2024-07-13 15:39:42

这是我经常使用的一种很好的循环形式。 您可以从 for 语句创建迭代变量,并且不需要检查 length 属性,这在迭代 NodeList 时尤其昂贵。 但是,您必须小心,如果数组中的任何值可能是“假”,您就不能使用它。 实际上,我仅在迭代不包含 null 的对象数组(如 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);
}

请注意,这也可以用于向后循环。

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

const a = ["a", "b", "c"];

for (const [index, element] of a.entries()) {
  console.log({index, element});
}

// If you don't need the index
for (const element of a) {
  console.log({element});
}
 

Here's a nice form of a loop I often use. You create the iterated variable from the for statement and you don't need to check the length property, which can be expensive specially when iterating through a NodeList. However, you must be careful, you can't use it if any of the values in array could be "falsy". In practice, I only use it when iterating over an array of objects that does not contain nulls (like a NodeList). But I love its syntactic sugar.

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);
}

Note that this can also be used to loop backwards.

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 Update

for...of can be used for a cleaner syntax. Available since ES6

const a = ["a", "b", "c"];

for (const [index, element] of a.entries()) {
  console.log({index, element});
}

// If you don't need the index
for (const element of a) {
  console.log({element});
}
 

久而酒知 2024-07-13 15:39:42

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

Note that in some cases, you need to loop in reverse order (but then you can use i-- too).

For example somebody wanted to use the new getElementsByClassName function to loop on elements of a given class and change this class. He found that only one out of two elements was changed (in FF3).
That's because the function returns a live NodeList, which thus reflects the changes in the Dom tree. Walking the list in reverse order avoided this issue.

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

In increasing index progression, when we ask the index 1, FF inspects the Dom and skips the first item with style2, which is the 2nd of the original Dom, thus it returns the 3rd initial item!

蓝礼 2024-07-13 15:39:42

我喜欢做:

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

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

I like doing:

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

There is no call to the length of the array on every iteration.

七颜 2024-07-13 15:39:42

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

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

I think using the first form is probably the way to go, since it's probably by far the most common loop structure in the known universe, and since I don't believe the reverse loop saves you any time in reality (still doing an increment/decrement and a comparison on each iteration).

Code that is recognizable and readable to others is definitely a good thing.

趁微风不噪 2024-07-13 15:39:42

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

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

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

I too advise to use the simple way (KISS !-)

-- but some optimization could be found, namely not to test the length of an array more than once:

var elements = document.getElementsByTagName('div');
for (var i=0, im=elements.length; im>i; i++) {
    doSomething(elements[i]);
}
笨死的猪 2024-07-13 15:39:42

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

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

我的问题是我期望 elements 是一个数组,但事实并非如此。 Document.getElementsByTagName() 返回的节点列表是可迭代的,但不能对其调用 array.prototype 方法。

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

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

之后,您可以随意调用 .innerHTML 或 .style 或对数组元素进行调用。

I had a very similar problem earlier with document.getElementsByClassName(). I didn't know what a nodelist was at the time.

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

My issue was that I expected that elements would be an array, but it isn't. The nodelist Document.getElementsByTagName() returns is iterable, but you can't call array.prototype methods on it.

You can however populate an array with nodelist elements like this:

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

After that you can feel free to call .innerHTML or .style or something on the elements of your array.

云之铃。 2024-07-13 15:39:42

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

编辑:这个答案是在 2008 年发布的。今天已经有了更好的结构。 这种特殊情况可以通过 .forEach 来解决。

At the risk of getting yelled at, i would get a javascript helper library like jquery or prototype they encapsulate the logic in nice methods - both have an .each method/iterator to do it - and they both strive to make it cross-browser compatible

EDIT: This answer was posted in 2008. Today much better constructs exist. This particular case could be solved with a .forEach.

画▽骨i 2024-07-13 15:39:42

另请参阅我对 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 毫秒。

反向 do/while: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 ms

反向 do/while:391,407,391,391,500,407,407,406,406,406

平均:411.20 ms。

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 毫秒。

反向 do/while:414,381,389,383,388,389,381,387,400,379

平均:389.10 毫秒。

Also see my comment on Andrew Hedges' test ...

I just tried to run a test to compare a simple iteration, the optimization I introduced and the reverse do/while, where the elements in an array was tested in every loop.

And alas, no surprise, the three browsers I tested had very different results, though the optimized simple iteration was fastest in all !-)

Test:

An array with 500,000 elements build outside the real test, for every iteration the value of the specific array-element is revealed.

Test run 10 times.

IE6:

Results:

Simple: 984,922,937,984,891,907,906,891,906,906

Average: 923.40 ms.

Optimized: 766,766,844,797,750,750,765,765,766,766

Average: 773.50 ms.

Reverse do/while: 3375,1328,1516,1344,1375,1406,1688,1344,1297,1265

Average: 1593.80 ms. (Note one especially awkward result)

Opera 9.52:

Results:

Simple: 344,343,344,359,343,359,344,359,359,359

Average: 351.30 ms.

Optimized: 281,297,297,297,297,281,281,297,281,281

Average: 289.00 ms

Reverse do/while: 391,407,391,391,500,407,407,406,406,406

Average: 411.20 ms.

FireFox 3.0.1:

Results:

Simple: 278,251,259,245,243,242,259,246,247,256

Average: 252.60 ms.

Optimized: 267,222,223,226,223,230,221,231,224,230

Average: 229.70 ms.

Reverse do/while: 414,381,389,383,388,389,381,387,400,379

Average: 389.10 ms.

哆兒滾 2024-07-13 15:39:42

Juan Mendez提供的循环形式非常有用和实用,
我稍微改变了它,现在它也适用于 - false、null、0 和空字符串。

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

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

Form of loop provided by Juan Mendez is very useful and practical,
I changed it a little bit, so that now it works with - false, null, zero and empty strings too.

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

for(var i = 0, item; (item = items[i]) !== undefined; i++)
{
    console.log("Index: " + i + "; Value: " + item);
}
维持三分热 2024-07-13 15:39:42

我知道这个问题很老了——但这是另一个非常简单的解决方案......

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

// Loop.
elements.forEach(function(value) {
  yourFunction(value);
});

I know this question is old -- but here's another, extremely simple solution ...

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

// Loop.
elements.forEach(function(value) {
  yourFunction(value);
});
缺⑴份安定 2024-07-13 15:39:42

我知道您不想听到这个,但是:我认为在这种情况下最佳实践是最具可读性的。 只要循环不从这里计数到月球,性能增益就不会足够大。

I know that you don't want to hear that, but: I consider the best practice is the most readable in this case. As long as the loop is not counting from here to the moon, the performance-gain will not be uhge enough.

尾戒 2024-07-13 15:39:42

我更喜欢 for 循环,因为它更具可读性。 从 length 到 0 的循环比从 0 到 length 的循环更有效。 正如您所说,使用反向 while 循环比 foo 循环更有效。 我不再有带有比较结果的页面的链接,但我记得不同的浏览器之间的差异有所不同。 对于某些浏览器来说,反向 while 循环的速度是原来的两倍。 但是,如果您循环“小”数组,则没有什么区别。 在您的示例中,元素的长度将是“小”

I prefer the for loop as it's more readable. Looping from length to 0 would be more efficient than looping from 0 to length. And using a reversed while loop is more efficient than a foor loop as you said. I don't have the link to the page with comparison results anymore but I remember that the difference varied on different browsers. For some browser the reversed while loop was twice as fast. However it makes no difference if you're looping "small" arrays. In your example case the length of elements will be "small"

堇年纸鸢 2024-07-13 15:39:42

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

I think you have two alternatives. For dom elements such as jQuery and like frameworks give you a good method of iteration. The second approach is the for loop.

上课铃就是安魂曲 2024-07-13 15:39:42

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

I like to use a TreeWalker if the set of elements are children of a root node.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文