HTMLC için toplama elemanları


405

Ben bir tüm öğelerin id almak ayarlamaya çalışıyorum HTMLCollectionOf. Aşağıdaki kodu yazdım:

var list = document.getElementsByClassName("events");
console.log(list[0].id);
for (key in list) {
    console.log(key.id);
}

Ama konsolda şu çıktıyı aldım:

event1
undefined

beklediğim gibi değil. Neden ikinci konsol çıktısı undefinedancak ilk konsol çıktısı event1?


23
soru for ... ifadesinde soru neden başlık "foreach" diyor? Buraya googling yaparken kazara geldim.
mxt3

@ mxt3 Anladığım kadarıyla, Java'daki her döngü için bir anologdu (aynı şekilde çalıştı).

1
@ mxt3 Aynı şeyi düşündüm! Ancak kabul edilen cevabı okuduktan sonra, Array.from () kullanarak foreach sorunumu çözen bu satırı buldum:Array.from(document.getElementsByClassName("events")).forEach(function(item) {
HoldOffHunger

Yanıtlar:


839

Orijinal soruya yanıt olarak for/inyanlış kullanıyorsunuz . Kodunuzda keydizin var. Yani, sözde diziden değeri almak için yapmanız list[key]ve kimliği almanız gerekir list[key].id. Ancak, bunu for/inilk etapta yapmamalısınız .

Özet (Ara 2018'de eklendi)

for/inBir nodeList veya HTMLCollection öğesini yinelemek için hiçbir zaman kullanmayın . Bundan kaçınmanın nedenleri aşağıda açıklanmıştır.

Modern tarayıcıların tüm son sürümleri (Safari, Firefox, Chrome, Edge) destekliyor for/ofnodeList veya gibi DOM listelerinde yinelemeyiHTMLCollection .

İşte bir örnek:

var list = document.getElementsByClassName("events");
for (let item of list) {
    console.log(item.id);
}

Eski tarayıcıları (IE gibi şeyler dahil) dahil etmek için, bu her yerde çalışır:

var list= document.getElementsByClassName("events");
for (var i = 0; i < list.length; i++) {
    console.log(list[i].id); //second console output
}

Neden Kullanmamanız Gerektiği Hakkında Açıklama for/in

for/in"" bir nesnenin özelliklerini yinelemek içindir. Bu, bir nesnenin tüm yinelenebilir özelliklerini döndüreceği anlamına gelir. Bir dizi için çalışıyor gibi görünse de (dönen elemanlar veya sözde dizi elemanları), nesnenin dizi benzeri elemanlardan beklediğiniz gibi olmayan diğer özelliklerini de döndürebilirsiniz. Ve bir HTMLCollectionveya nodeListnesnenin her ikisinin de for/inyinelemeyle döndürülecek başka özellikleri olabileceğini tahmin edin . Sadece Chrome'da bunu denedim ve yinelediğiniz şekilde yineledim, listedeki öğeleri (0, 1, 2, vb ...) alır, ancak lengthve itemözelliklerini de alır . for/inYineleme sadece bir HTMLCollection için çalışmaz.


Bkz. Http://jsfiddle.net/jfriend00/FzZ2H/Bir HTMLCollection'ı neden tekrarlayamamanız için adresinefor/in .

Firefox'ta for/inyinelemeniz şu öğeleri döndürür (nesnenin tüm yinelenebilir özellikleri):

0
1
2
item
namedItem
@@iterator
length

Umarım, şimdi neden kullanmak istediğinizi görebilirsiniz , for (var i = 0; i < list.length; i++)böylece elde edersiniz ve012 senin tekrarında.


Aşağıda, tarayıcıların 2015-2018 dönemi boyunca nasıl evrimleştiğinin bir evrimi vardır. Yukarıda açıklanan seçenekleri kullanabileceğiniz için modern tarayıcılarda bunlara artık gerek yoktur.

2015'te ES6 Güncellemesi

ES6'ya, Array.from()dizi benzeri bir yapıyı gerçek bir diziye dönüştürecek olan eklenir . Bu, kişinin doğrudan böyle bir liste numaralandırmasına izin verir:

"use strict";

Array.from(document.getElementsByClassName("events")).forEach(function(item) {
   console.log(item.id);
});

Çalışan demo (Nisan 2016 itibariyle Firefox, Chrome ve Edge'de): https://jsfiddle.net/jfriend00/8ar4xn2s/


2016'da ES6 Güncellemesi

Artık ES6'yı a NodeListve an ile birlikte / of construct için HTMLCollectionyalnızca kodunuza ekleyerek kullanabilirsiniz:

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

Sonra şunları yapabilirsiniz:

var list = document.getElementsByClassName("events");
for (var item of list) {
    console.log(item.id);
}

Bu, Chrome, Firefox ve Edge'in geçerli sürümünde çalışır. Bu, Array yineleyicisini hem NodeList hem de HTMLCollection prototiplerine eklediği için çalışır, böylece yinelendiğinde / yinelendiğinde bunları yinelemek için Array yineleyicisini kullanır.

Çalışma demosu: http://jsfiddle.net/jfriend00/joy06u4e/ .


Aralık 2016'da ES6 için İkinci Güncelleme

Aralık 2016 itibariyle, Symbol.iteratorChrome v54 ve Firefox v50'de destek sağlanmıştır , bu nedenle aşağıdaki kod kendi kendine çalışır. Edge için henüz yerleşik değil.

var list = document.getElementsByClassName("events");
for (let item of list) {
    console.log(item.id);
}

Çalışan demo (Chrome ve Firefox'ta): http://jsfiddle.net/jfriend00/3ddpz8sp/

Aralık 2017'de ES6 için Üçüncü Güncelleme

Aralık 2017 itibariyle, bu özellik Edge 41.16299.15.0'da nodeListolduğu gibi çalışır document.querySelectorAll(), ancak HTMLCollectionolduğu gibi değil , document.getElementsByClassName()bu nedenle yineleyiciyi Edge'de bir için kullanmak üzere manuel olarak atamanız gerekir HTMLCollection. Bir koleksiyon türünü neden düzelttikleri tam bir gizem, diğerini değil. Ancak, en azından Edge'in şu anki sürümlerinde document.querySelectorAll()ES6 for/ofsözdiziminin sonucunu kullanabilirsiniz .

Ben de hem jsFiddle hem de ayrı ayrı test eder HTMLCollectionve nodeListçıktı jsFiddle kendisi yakalar.

ES6 için Mart 2018'de Dördüncü Güncelleme

Mesqueeeb Başına, Symbol.iteratordestek yerleşik olan Safari de kullanabilirsiniz, böylece for (let item of list)biri için document.getElementsByClassName()veyadocument.querySelectorAll() .

ES6 için Nisan 2018'de Beşinci Güncelleme

Görünüşe göre, bir HTMLCollectionile yineleme desteği for/of2018 Sonbaharında Edge 18'e gelecek.

Kasım 2018'de ES6 için Altıncı Güncelleme

Microsoft Edge v18 (Sonbahar 2018 Windows Güncelleştirmesi'nde bulunan) ile artık hem HTMLCollection'ı hem de Edge for / ile birlikte bir NodeList'i yineleyebileceğinizi onaylayabilirim.

Bu nedenle, şimdi tüm modern tarayıcılar for/ofhem HTMLCollection hem de NodeList nesnelerinin yinelenmesi için yerel destek içerir .


1
JS güncellendiği için çok ayrıntılı güncellemeler için teşekkür ederiz. Bu, yeni başlayanların bu tavsiyeyi yalnızca belirli bir JS sürümü için geçerli olan diğer makaleler / yayınlar bağlamında anlamalarına yardımcı olur.
brownmagik352

Üstün cevap, şaşırtıcı güncelleme desteği .. Teşekkür ederim.
cossacksman

79

for/ inOn NodeLists veya HTMLCollections kullanamazsınız . Bununla birlikte, bazı Array.prototypeyöntemleri, siz sürece .call()ve olarak NodeListveya geçtiğiniz sürece kullanabilirsiniz .HTMLCollectionthis

Bu yüzden aşağıdakileri jfriend00'ün fordöngüsüne alternatif olarak düşünün :

var list= document.getElementsByClassName("events");
[].forEach.call(list, function(el) {
    console.log(el.id);
});

MDN hakkında bu tekniği kapsayan iyi bir makale var . Ancak tarayıcı uyumluluğu hakkındaki uyarılarına dikkat edin:

[...] bir ana bilgisayar nesnesini (a gibi NodeList) thisyerel bir yönteme (örneğin forEach) geçirmenin tüm tarayıcılarda çalışacağı garanti edilmez ve bazılarında başarısız olduğu bilinmektedir.

Dolayısıyla bu yaklaşım uygun olsa da, bir fordöngü tarayıcıyla en uyumlu çözüm olabilir.

Güncelleme (30 Ağu 2014): Sonunda ES6 for/of !

var list = document.getElementsByClassName("events");
for (const el of list)
  console.log(el.id);

Chrome ve Firefox'un son sürümlerinde zaten desteklenmektedir.


1
Çok hoş! Bu tekniği a'dan seçilen seçeneklerin değerlerini almak için kullandım <select multiple>. Örnek:[].map.call(multiSelect.selectedOptions, function(option) { return option.value; })
XåpplI'-I0llwlg'I -

1
Bunun için bir ES2015 çözümü arıyordum, bu yüzden for ... ofçalıştığını onayladığınız için teşekkürler .
Richard Turner

60

ES6 olarak, bir şey gibi yapabileceği [...collection]veya Array.from(collection),

let someCollection = document.querySelectorAll(someSelector)
[...someCollection].forEach(someFn) 
//or
Array.from(collection).forEach(someFn)

Örneğin:-

    navDoms = document.getElementsByClassName('nav-container');
    Array.from(navDoms).forEach(function(navDom){
     //implement function operations
    });

@DanielM tahmin ne yaptım, bir dizi benzeri bir yapı sığ klon
mido

Anladım, teşekkürler - şimdi aradığım belgeleri buldum: developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
DanielM

Bunu her zaman kullanıyorum, gözler için Array.from'dan çok daha kolay, sadece önemli bir performans veya bellek dezavantajı olup olmadığını merak ediyorum. Örneğin, bir tablo satırının hücrelerini yinelemem gerekiyorsa [...row.cells].forEachbunun yerine birrow.querySelectorAll('td')
Mojimi

16

bu iki satırı ekleyebilirsiniz:

HTMLCollection.prototype.forEach = Array.prototype.forEach;
NodeList.prototype.forEach = Array.prototype.forEach;

HTMLCollection getElementsByClassName ve getElementsByTagName tarafından döndürülür

NodeList , querySelectorAll tarafından döndürülür

Bunun gibi bir forEach yapabilirsiniz:

var selections = document.getElementsByClassName('myClass');

/* alternative :
var selections = document.querySelectorAll('.myClass');
*/

selections.forEach(function(element, i){
//do your stuffs
});

Bu cevap çok etkili görünüyor. Ne bulundu?
Peheje

2
Yakalama bu çözüm IE11 üzerinde çalışmıyor olmasıdır! Gerçi iyi bir çözüm.
Rahul Gaba

2
NodeListZaten varforEach() olduğunu unutmayın .
Franklin Yu

7

IE 11'de forEach kullanırken bir sorun yaşadım ve ayrıca Firefox 49'da

Böyle bir çözüm buldum

Array.prototype.slice.call(document.getElementsByClassName("events")).forEach(function (key) {
        console.log(key.id);
    }

IE11 için harika bir çözüm! Eskiden yaygın bir teknik ...
mb21

6

Alternatif olarak Array.fromkullanmakArray.prototype.forEach.call

her biri için: Array.prototype.forEach.call(htmlCollection, i => { console.log(i) });

map: Array.prototype.map.call(htmlCollection, i => { console.log(i) });

vb ...


6

forIE9 veya üstündeyseniz döngüden kaçmak için es6 özelliklerini kullanmanız için hiçbir neden yoktur .

ES5'te iki iyi seçenek var. Öncelikle, "ödünç" olabilir Array's forEacholarak evan bahseder .

Ama daha da iyisi ...

Kullanım Object.keys(), yok olması forEachve filtreler otomatik olarak "kendi özellikleri" için.

Yani, Object.keysesasen a for... inile yapmakla eşdeğerdir HasOwnProperty, ancak çok daha pürüzsüzdür.

var eventNodes = document.getElementsByClassName("events");
Object.keys(eventNodes).forEach(function (key) {
    console.log(eventNodes[key].id);
});

5

Mart 2016 itibariyle, Chrome 49.0'da şunlar for...ofiçin çalışır HTMLCollection:

this.headers = this.getElementsByTagName("header");

for (var header of this.headers) {
    console.log(header); 
}

Buradaki belgelere bakın .

Ancak, yalnızca aşağıdakileri kullanmadan önce aşağıdaki geçici çözümü uygularsanız çalışır for...of:

HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

Bunun kullanılması için gerekli olan for...ofile NodeList:

NamedNodeMap.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];

for...ofYakında yukarıdaki geçici çözüm olmadan çalışacağına inanıyorum / umarım . Açık olan konu şudur:

https://bugs.chromium.org/p/chromium/issues/detail?id=401699

Güncelleme: Aşağıdaki Expenzor'un yorumuna bakın: Nisan 2016 itibarıyla düzeltildi. HTMLCollection.prototype [Symbol.iterator] = Array.prototype [Symbol.iterator] eklemenize gerek yok; için bir HTMLCollection üzerinden yineleme yapmak


4
Bu, Nisan 2016 itibarıyla düzeltildi . HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];Bir HTMLCollectionile yinelemeye eklemenize gerek yok for...of.
Expenzor

3

Sınırda

if(!NodeList.prototype.forEach) {
  NodeList.prototype.forEach = function(fn, scope) {
    for(var i = 0, len = this.length; i < len; ++i) {
      fn.call(scope, this[i], i, this);
    }
  }
}

2

Her zaman kullandığım kolay geçici çözüm

let list = document.getElementsByClassName("events");
let listArr = Array.from(list)

Bundan sonra, seçimde istediğiniz Array yöntemlerini çalıştırabilirsiniz

listArr.map(item => console.log(item.id))
listArr.forEach(item => console.log(item.id))
listArr.reverse()

1

ES'nin eski sürümlerini (örneğin ES5) kullanıyorsanız şunları kullanabilirsiniz as any:

for (let element of elementsToIterate as any) {
      console.log(element);
}

0

Bunu değiştirmek istiyorsun

var list= document.getElementsByClassName("events");
console.log(list[0].id); //first console output
for (key in list){
    console.log(list[key].id); //second console output
}

5
FYI, bunun neden düzgün çalışmadığına dair cevabımı gör. Bu , koleksiyondaki öğeler olması amaçlanmayan for (key in list)birçok özelliğini döndürür HTMLCollection.
jfriend00
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.