GetElementsByClassName'deki bir dizide forEach kullanılması "TypeError: undefined bir işlev değildir" sonucunu verir


92

In my JSFiddle , ben sadece bir dizi eleman üzerinde yineleme çalışıyorum. Günlük ifadelerinin de kanıtladığı gibi dizi boş değildir. Yine de, çağrısı forEachbana (o kadar yararlı değil) “Yakalanmamış TypeError: undefinedbir işlev değil” hatası veriyor .

Aptalca bir şey yapıyor olmalıyım; Neyi yanlış yapıyorum?

Kodum:

var arr = document.getElementsByClassName('myClass');
console.log(arr);
console.log(arr[0]);
arr.forEach(function(v, i, a) {
  console.log(v);
});
.myClass {
  background-color: #FF0000;
}
<div class="myClass">Hello</div>


8
arrbir dizi değil, a HTMLCollection. Bir dizi ile aynı yöntemlere sahip değildir. developer.mozilla.org/en-US/docs/Web/API/… . İşte bununla ilgili bir SO gönderisi: stackoverflow.com/questions/13433799/…
Ian

Gibi bir [1,2,3].forEach(function(v,i,a) { console.log(v); });şey iyidir. Bu ve benim örneğimdeki dizi arasındaki fark nedir?
Jer

Örneğinizde bir dizi yok . Bunun bir dizi olduğunu düşündüren nedir?
Ian

3
@Jer: de arr instanceof Arrayneden olur falseherhangi prototip yöntemleri boşuna olamaz bunun Arraygibi bir nesne () Array.prototype.forEach . arrbir HTMLCollection ve dizi benzeri bir nesnedir (ancak miras almaz veya somutlaştırmaz Array). Dolayısıyla, standart fordöngünüz, nesnenin dizini boyunca yinelenen ve bir prototip olmadığı için çalışacaktır Array.
Hayır

1
@ Jer — yerleşik ve barındırılan nesneler arasındaki farklara bakmalısınız. İlki ECMA-262'ye uygundur, daha sonra yalnızca ev sahibinin istediği kadar. DOM, çoğunlukla NodeList arabirimine dayalı olarak üyelere dizin (belge.görüntüler, belge.formlar, form. öğeler, seçim. seçenekler, vb.) Göre erişime izin veren birçok nesneye sahiptir .
RobG

Yanıtlar:


164

Bunun nedeni , bir dizi değil, HTMLCollectiondocument.getElementsByClassName döndürmesidir .

Neyse ki bu "dizi benzeri" bir nesnedir (bu, neden bir nesneymiş gibi günlüğe kaydedildiğini ve neden standart bir fordöngü ile yineleyebileceğinizi açıklar ), böylece bunu yapabilirsiniz:

[].forEach.call(document.getElementsByClassName('myClass'), function(v,i,a) {

ES6 ile (modern tarayıcılarda veya Babel ile), Array.fromdizi benzeri nesnelerden dizileri oluşturan dizileri de kullanabilirsiniz :

Array.from(document.getElementsByClassName('myClass')).forEach(v=>{

veya dizi benzeri nesneyi bir diziye yayın:

[...document.getElementsByClassName('myClass'))].forEach(v=>{

2
@Jer argumentsbiridir. jQuery nesneleri başka bir şeydir. Kendiniz bir tane yapabilirsiniz:var a = {"0": "str1", "1": "str2", length: 2}
Ian

1
Burada yine eski tarayıcılara gidiyoruz… bir ana bilgisayar nesnesini yerel bir yönteme geçirmek IE 8 ve daha düşük sürümlerde başarısız olacaktır. Belki kimsenin umurunda değil, ama bazıları olabilir. ;-) Oh, getElementsByClassName'i de desteklemiyor , ama querySelectorAll('.myClass')çalışmalı. Hala yineleyicilerin NodeList API'sine eklenmesini bekliyorum. :-(
RobG

2
@Jer: Bir yan not olarak, herhangi bir nedenle döngüden çıkmayı düşünüyorsanız, Array.prototype.forEachbunu yapmanıza izin vermez. Bu gereksinime daha sonra sahipseniz standart fordöngüyü kullanın Array.prototype.everyveya dizi nesnesini kullanmak istiyorsanız veya kullanın Array.prototype.some(her / bazılarının IE8 veya daha azında desteklenmediğini unutmayın)
Hayır

1
@Ian Nesnenin "dizi benzeri" olması için eke ihtiyacınız var. Günlükleri burada karşılaştırın: jsbin.com/sigut/1/edit
Denys Séguret

1
@Ian TBH "dizi benzeri" nin tanımı çok belirsizdir ve kullanıma bağlıdır. Bazen içermez spliceo tanımında ama daha "dizi benzeri" olmak istediğinizde kullanmak mümkün map, filterve benzeri, o zaman bunu içerir. Kullanarak basit yineleme forEachgerekmez splice.
Denys Séguret

11

Bunu deneyin, işe yaramalı:

<html>
  <head>
    <style type="text/css">
    </style>
  </head>
  <body>
   <div class="myClass">Hello</div>
   <div class="myClass">Hello</div>

<script type="text/javascript">
    var arr = document.getElementsByClassName('myClass');
    console.log(arr);
    console.log(arr[0]);
    arr = [].slice.call(arr); //I have converted the HTML Collection an array
    arr.forEach(function(v,i,a) {
        console.log(v);
    });
</script>


<style type="text/css">
    .myClass {
    background-color: #FF0000;
}
</style>

  </body>
</html>

0

Belirli bir sınıftaki her öğenin kimliğine erişmek istemeniz durumunda aşağıdakileri yapabilirsiniz:

    Array.from(document.getElementsByClassName('myClass')).forEach(function(element) {
        console.log(element.id);
    });
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.