簡體   English   中英

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

[英]What's the best way to loop through a set of elements in JavaScript?

在過去和大多數我目前的項目中,我傾向於使用這樣的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中的元素或任何數組的最佳實踐?

這是我經常使用的一個很好的循環形式。 您可以從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);
}

請注意,在某些情況下,您需要以相反的順序循環(但是您也可以使用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個初始項目!

我喜歡這樣做:


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

每次迭代都沒有調用數組的長度。

冒着被大吼大叫的風險,我會得到一個像jquery或者原型這樣的javascript助手庫,它們將邏輯封裝在漂亮的方法中 - 兩者都有一個.each方法/迭代器來做 - 並且他們都努力使它跨瀏覽器兼容

編輯:這個答案發布於2008年。今天存在更好的結構。 這個特殊情況可以通過.forEach來解決。

我認為使用第一種形式可能是要走的路,因為它可能是迄今為止已知宇宙中最常見的循環結構,並且因為我不相信反向循環可以在實際中節省你的任何時間(仍在增加/遞減和每次迭代的比較)。

其他人可識別和可讀的代碼絕對是件好事。

我之前遇到過與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或類似元素的內容。

我也建議使用簡單的方式(KISS! - )

- 但是可以找到一些優化,即不要多次測試數組的長度:

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

另請參閱我對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毫秒。

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

我知道你不想聽到這個,但是:我認為在這種情況下最好的做法是最可讀的。 只要循環不計數從這里到月球,性能增益就不夠了。

我更喜歡for循環,因為它更具可讀性。 從長度到0的循環比從0到長度的循環更有效。 如你所說,使用反向while循環比foor循環更有效。 我沒有比較結果頁面的鏈接,但我記得不同瀏覽器的差異各不相同。 對於某些瀏覽器,反向while循環速度是其兩倍。 但是,如果你循環“小”數組,它沒有任何區別。 在您的示例中,元素的長度將是“小”

我認為你有兩種選擇。 對於諸如jQuery和類似框架之類的dom元素,為您提供了一種很好的迭代方法。 第二種方法是for循環。

我知道這個問題很老 - 但這是另一個非常簡單的解決方案......

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

然后它可以像任何標准數組一樣使用。

如果元素集是根節點的子節點,我喜歡使用TreeWalker

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM