Javascript'te her dizi için?

Bir dizindeki tüm girişleri javascript kullanarak nasıl görebilirim?

Bunun gibi bir şey olduğunu düşündüm:

 forEach(instance in theArray) 

theArray olduğu yer, ama yanlış görünüyor.

4041
17 февр. Dante1986 , 17 Şubat'ta ayarlandı 2012-02-17 16:51 '12 4:51 PM 2012-02-17 16:51
@ 32 cevap
  • 1
  • 2

TP; DR

  • Koruma ile kullanmıyorsanız veya en azından sizi neden ısırdığını bilmiyorsanız for-in kullanmayın.
  • En iyi bahislerin genellikle

    • döngü için (yalnızca ES2015 + için),
    • Array#forEach ( spec | MDN ) (veya some akrabaları) (yalnızca ES5 +)
    • basit eski döngüler for moda
    • veya korumalı giriş girişi.

Ama hala keşfedilecek, okunacak çok şey var ...


JavaScript, dizileri ve dizi türündeki nesneleri döngüsel olarak dönüştürmek için güçlü bir semantikaya sahiptir. Cevabı iki bölüme ayırdım: otantik diziler için seçenekler ve sadece arguments nesnesi, diğer yinelenebilir nesneler (ES2015 +), DOM koleksiyonları gibi dizilere benzer şeyler için seçenekler

ES2015'i ES5'e göndererek, ES515 seçeneklerini, hatta ES5 motorlarında bile kullanabileceğinizi hemen anlıyorum. Daha fazla bilgi için "ES2015 nakli" / "ES6 nakli" öğesini bulun ...

Peki, seçeneklere bak:

Gerçek diziler için

Şu anda en çok desteklenen sürüm olan ECMAScript 5'te ("ES5") ve ECMAScript 2015'te ("ES2015", "ES6") eklenen iki seçeneğiniz var:

  1. Her bir kullanım ve ilgili (ES5 +)
  2. Döngü for basit kullanın
  3. for-in in'i doğru kullan
  4. Şunun for-of kullan (örtülü yineleyici kullan) (ES2015 +)
  5. Açık bir şekilde yineleyici kullan (ES2015 +)

ayrıntıları:

1. Her bir kullanım ve ilgili

ES5'in eklediği Array işlevlerine (doğrudan veya polyple dolgular kullanarak) erişebildiğiniz süresiz modern ortamlarda (yani, IE8'de değil), forEach ( spec | MDN ) 'ı kullanabilirsiniz:

 var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); }); 

forEach bir geri çağırma işlevini ve isteğe bağlı olarak, bu geri çağrıyı çağırırken bu şekilde kullanılan bir değeri kabul eder (yukarıda kullanılmaz). Seyrek dizilerde var olmayan girdileri atlamak için dizideki her giriş için geri çağırma çağrılır. Yukarıdaki tek bir argüman kullanmama rağmen, geri çağrı üç ile çağrılır: her kaydın değeri, bu kaydın indeksi ve tekrarladığınız dizinin bağlantısı (fonksiyonunuz zaten yoksa).

IE8 (NetApps'in Eylül 2016'da bu yazının yazıldığı tarihte pazarın% 4'ünden fazlasını gösterdiği gibi) gibi eski tarayıcıları desteklemiyorsanız, sayfa düzeni olmadan evrensel bir web sayfasında forEach kullanabilirsiniz. Güncel olmayan tarayıcıları desteklemeniz gerekiyorsa, HerE işlemi için düzeltme / çoklu doldurma işlemini gerçekleştirmek kolaydır (çeşitli seçenekler için "es5 shim" i bulun).

forEach , içerik alanında indeksleme ve değişken değerler bildirmeniz gerekmediğinden, yineleme işlevine bağımsız değişkenler sağladıkları ve bu yinelemeye çok iyi yönlendirdikleri için avantajı vardır.

Her dizi kaydı için bir işlev çağrısının yürütülmesi için geçen süre konusunda endişeleriniz varsa; ayrıntılar .

Buna ek olarak, forEach bir "hepsi arasında döngü" işlevidir, ancak ES5 aşağıdakiler de dahil olmak üzere birkaç diğer yararlı "dizi işlevleri ve şeylerle yapılan eklemeleri" tanımlamıştır:

  • every (geri çağrı false veya yanlış bir şey döndürdüğünde döngüyü durdurur)
  • some (geri arama ilk kez true döndüğünde veya mantıklı bir şey olduğunda döngüyü durdurur)
  • filter (filter işlevinin true döndürdüğü ve false döndürdüğü noktaları çıkartan öğeleri içeren yeni bir dizi oluşturur)
  • map (yeni bir geri dönüş geri arama değeri dizisi oluşturur)
  • reduce (bir değeri artırma, geri çağırma işlevini yeniden başlatma, önceki değerleri geçirme, ayrıntılar için özelliğe bakın, bir dizinin içeriğini ve diğer birçok şeyi toplamak için yararlıdır)
  • reduceRight (örneğin, reduce , ancak artan sırada değil, azalan sırada çalışır)

2. Döngü for basit bir kullanın

Bazen eski yollar en iyisidir:

 var index; var a = ["a", "b", "c"]; for (index = 0; index < a.length; ++index) { console.log(a[index]); } 

Dizi uzunluğu döngü boyunca değişmezse ve performansı hassas kodsa (olası değildir), yakalamanın ön uzunluğu biraz daha karmaşık bir sürümü biraz daha hızlı olabilir:

 var index, len; var a = ["a", "b", "c"]; for (index = 0, len = a.length; index < len; ++index) { console.log(a[index]); } 

Ve / veya geri sayım:

 var index; var a = ["a", "b", "c"]; for (index = a.length - 1; index >= 0; --index) { console.log(a[index]); } 

Ancak modern JavaScript mekanizmalarında, bu son meyve suyunu nadiren kazmanız gerekir.

ES2015 ve daha yüksek sürümlerde, endeks ve değer değişkenlerinizi döngüler for yerel yapabilirsiniz:

 let a = ["a", "b", "c"]; for (let index = 0; index < a.length; ++index) { let value = a[index]; } //console.log(index); // Would cause "ReferenceError: index is not defined" //console.log(value); // Would cause "ReferenceError: value is not defined" 

Ve bunu yaptığınızda, sadece value değil, aynı zamanda index , döngünün her yinelemesi için yeniden yaratılır, yani, döngü etiketinde oluşturulan kapaklar, bu belirli yineleme için yaratılan index (ve value ) bir referans içerir:

 let divs = document.querySelectorAll("div"); for (let index = 0; index < divs.length; ++index) { divs[index].addEventListener('click', e => { alert("Index is: " + index); }); } 

Beş div'iniz olsaydı, ilkini tıklarsanız, son dizini tıklattığınızda "Dizin: 0" olur. Eğer let yerine var kullanırsanız bu işe yaramaz.

3. for-in uygun şekilde kullanın.

İnsanlara size for-in kullanmalarını söylettirirsiniz ancak bu for-in ne değildir . for-in dizinin dizinlerini değil, nesnenin numaralandırılmış özelliklerini kullanarak yazılır. ES2015'te (ES6) bile sipariş garanti edilmez. ES2015, bir nesnenin özelliklerinin sırasını belirler ( [[OwnPropertyKeys]] , [[Enumerate]] ve bunları onları Object.getOwnPropertyKeys olarak kullanan şeyler) belirler, ancak for-in Object.getOwnPropertyKeys bu sırayı izleyeceğini belirtmez. ( Bu cevaptaki detaylar .)

Ancak, özellikle uygun önlemler kullanıyorsanız, özellikle seyrek diziler için yararlı olabilir:

 // 'a' is a sparse array var key; var a = []; a[0] = "a"; a[10] = "b"; a[10000] = "c"; for (key in a) { if (a.hasOwnProperty(key)  // These are explained /^0$|^[1-9]\d*$/.test(key)  // and then hidden key <= 4294967294 // away below ) { console.log(a[key]); } } 

İki çeke dikkat edin:

  1. Nesnenin bu isim altında kendi özelliğine sahip olması (ve prototipinden miras kalanı değil) ve

  2. Anahtarın normal dize biçimindeki 10 tabanlı bir sayısal dize olduğu ve değerinin <= 2 ^ 32 - 2 (4,294,967,294) olduğu. Bu numara nereden geliyor? Bu, spesifikasyondaki dizi indeksi tanımının bir parçasıdır. Diğer sayılar (tamsayı olmayan sayılar, negatif sayılar, 2 ^ 32 - 2'den büyük sayılar) dizi indeksleri değildir. 2 ^ 32 - 2'nin nedeni, en yüksek indeks değerini length dizinin length maksimum değeri olan 2 ^ 32 - 1'den daha az yapan şeydir. (Örneğin, dizi uzunluğu bir 32 bit işaretsiz tamsayıya karşılık gelir.) (Bir yorumda , önceki testimin doğru olmadığına dair bir açıklamada RobG tarafından yapılan bir onay).

Bu, çoğu dizideki döngülerdeki her yineleme için küçük bir ek yük ekidir, ancak seyrek bir diziniz varsa, bu döngü için daha etkili bir yol olabilir, çünkü bunlar yalnızca gerçekten var olan kayıtlar için döngülerdir. Örneğin, yukarıdaki dizi için üç kez ( "0" , "10" ve "10000" tuşları için hatırlayın, bunlar satırdır), 10.001 kez değil.

Şimdi her seferinde yazmak istemezsiniz, böylece araç kitinize koyabilirsiniz:

 function arrayHasOwnIndex(array, prop) { return array.hasOwnProperty(prop)  /^0$|^[1-9]\d*$/.test(prop)  prop <= 4294967294; // 2^32 - 2 } 

Ve sonra bunu şöyle kullanacağız:

 for (key in a) { if (arrayHasOwnIndex(a, key)) { console.log(a[key]); } } 

Veya, yalnızca “çoğu durumda yeterince iyi” testiyle ilgileniyorsanız, onu kullanabilirsiniz, ancak yakın olduğu sürece, bu doğru değildir:

 for (key in a) { // "Good enough" for most cases if (String(parseInt(key, 10)) === key  a.hasOwnProperty(key)) { console.log(a[key]); } } 

4. Kullanım for-of kullan (örtük yineleyici kullan) (ES2015 +)

ES2015, yineleyicileri JavaScript'e ekler. Yineleyicileri kullanmanın en kolay yolu, yeni işleç kullanıcısıdır. Bu gibi görünüyor:

 var val; var a = ["a", "b", "c"]; for (val of a) { console.log(val); } 

Sonuç:

 bir b c

Diziden bir yineleyici alan ve içinden geçen kapakların altından değerler alır. for-in kullanımıyla ilgili hiçbir sorunu yoktur, çünkü bir nesne (dizi) tarafından tanımlanan bir yineleyici kullanır ve diziler yineleyicilerinin kayıtlarını (özelliklerini değil) tekrar ettiğini belirler. ES5'teki girişlerden farklı for-in , kayıtların görüntülenme sırası dizinlerinin sayısal sırasıdır.

5. Yineleyiciyi açıkça kullanın (ES2015 +)

Bazen açıkça bir yineleyici kullanabilirsiniz. Siz de bunu yapabilirsiniz, çünkü her şeyden daha beceriksizdir. Bu gibi görünüyor:

 var a = ["a", "b", "c"]; var it = a.values(); var entry; while (!(entry = it.next()).done) { console.log(entry.value); } 

Bir yineleyici, belirtmedeki yineleyicinin tanımına uyan bir nesnedir. Bir next yöntemi, onu her çağırışınızda yeni bir sonuç nesnesi döndürür. Sonuç nesnesi, yapılmış bir özelliğe sahip olup olmadığını ve bu yinelemenin değeri value özelliğin value bize bildirir. ( false olursa, isteğe bağlı, undefined değilse value isteğe bağlıdır).

value , yineleyiciye bağlı olarak değişir; diziler yineleyiciler döndüren (en az) üç işlevi destekler:

  • values() : Yukarıda kullandığım değer. Her yinelemenin bu yineleme için bir dizi kaydı olduğu bir yinelemeci döndürür (yukarıdaki örnekte "a" , "b" ve "c" ).
  • keys() : Her bir value , bu yinelemenin anahtarı olduğu bir yineleyici döndürür (bizim için yukarıdaki "0" , sonra "1" ve sonra "2" ).
  • entries() : bir yineleyici döndürür, burada her value bu yineleme için [key, value] biçiminde bir dizidir.

Dizi benzeri nesneler için

Gerçek dizilere ek olarak, length özelliğine ve sayısal adlara sahip özelliklere sahip dizi benzeri nesneler de vardır: NodeList örnekleri, bir arguments nesnesi, vb. İçeriğini nasıl NodeList ?

Diziler için yukarıdaki parametrelerden birini kullanın.

En azından bazıları ve belki de yukarıdaki dizilerin çoğu veya hatta tümü, dizi türündeki nesneler için genellikle eşit derecede iyi kullanılır:

  1. Her bir kullanım ve ilgili (ES5 +)

    Array.prototype çeşitli işlevler "kasıtlı olarak geneldir" ve genellikle Function#call Function#apply veya Function#apply ile bir dizi gibi nesneler için kullanılabilir. (Bu yanıtın sonunda ev sahibi tarafından sağlanan nesneler için Yasal Uyarı'ya bakın, ancak bu nadir bir sorundur.)

    childNodes Node childNodes içindeki Her for öğesini kullanmak istediğinizi varsayalım. Bunu yapardın:

     Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with 'child' }); 

    Bunu çok yapacaksanız, işlev referansının bir kopyasını tekrar kullanılacak bir değişkende almak isteyebilirsiniz, örneğin:

     // (This is all presumably in some scoping function) var forEach = Array.prototype.forEach; // Then later... forEach.call(node.childNodes, function(child) { // Do something with 'child' }); 
  2. Döngü for basit kullanın

    Açıkçası, bir döngü for basit bir döngü, bir dizi gibi nesnelere uygulanır.

  3. for-in in'i doğru kullan

    bir dizi ile aynı garantilerde olduğu için, bir diziye benzer nesnelerle çalışmalıdır; Ev sahibi tarafından sağlanan ürünler için yukarıdaki 1 numara için rezervasyon yapılması gerekebilir.

  4. Şunun for-of kullan (örtülü yineleyici kullan) (ES2015 +)

    for-of , eğer varsa, nesne tarafından sağlanan yineleyiciyi kullanır; Bunun çeşitli dizi benzeri nesnelerde, özellikle de ana bilgisayar dosyalarında nasıl olduğunu görmemiz gerekecek. Örneğin, querySelectorAll NodeList belirtimi yinelemeyi desteklemek için güncellendi. getElementsByTagName HTMLCollection için HTMLCollection değildi.

  5. Açık bir şekilde yineleyici kullan (ES2015 +)

    Sayı 4'e bakın, yineleyicilerin nasıl açıldığını görmemiz gerekir.

Gerçek bir dizi oluşturun

Diğer durumlarda, bir dizi gibi bir nesneyi gerçek bir diziye dönüştürebilirsiniz. Bunu yapmak şaşırtıcı derecede kolaydır:

  1. slice dizisi yöntemini kullanın

    Yukarıda belirtilen diğer yöntemler gibi "kasıtlı olarak genel" olan ve bu nedenle dizi benzeri nesnelerle kullanılabilen slice dizisi yöntemini kullanabiliriz, örneğin:

     var trueArray = Array.prototype.slice.call(arrayLikeObject); 

    Örneğin, bir NodeList gerçek bir diziye dönüştürmek istiyorsak, şunu yapabiliriz:

     var divs = Array.prototype.slice.call(document.querySelectorAll("div")); 

    Aşağıdaki "Ana bilgisayar tarafından sağlanan nesneler için dikkat" bölümüne bakın. Özellikle, bunun IE8 ve önceki sürümlerinde çalışmayacağını, bunun gibi ana bilgisayar tarafından sağlanan nesnelerin kullanımına izin vermeyeceğini unutmayın.

  2. Dağıtım sözdizimini kullan ( ... )

    ES2015 dağıtım sözdizimini, bu özelliği destekleyen JavaScript mekanizmalarıyla birlikte kullanmak da mümkündür:

     var trueArray = [...iterableObject]; 

    Dolayısıyla, örneğin, bir NodeList gerçek bir diziye dönüştürmek istiyorsak, yayılma sözdizimini kullanarak, kısa olur:

     var divs = [...document.querySelectorAll("div")]; 
  3. Array.from (spec) kullanın | (MDN)

    Array.from (ES2015 +, ancak kolayca poli doldurulur), gerekirse, önce eşleştirme işlevinden kayıtları geçen bir dizi gibi bir nesneden bir dizi oluşturur. böylece:

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

    Veya, belirli bir sınıfa sahip öğeler için bir dizi etiket adı almak istiyorsanız, mapping işlevini kullanmanız gerekir:

     // Arrow function (ES2015): var divs = Array.from(document.querySelectorAll(".some-class"), element => element.tagName); // Standard function (since 'Array.from' can be shimmed): var divs = Array.from(document.querySelectorAll(".some-class"), function(element) { return element.tagName; }); 

Ana bilgisayar tarafından sağlanan tesisler için dikkat

Ana bilgisayar gibi nesnelerle Array.prototype işlevlerini kullanıyorsanız (DOM listeleri ve JavaScript motoru yerine tarayıcı tarafından sağlanan diğer şeyler), sağlanan ana makine nesnesinin davranışlarını doğrulamak için hedef ortamlarınızda test ettiğinizden emin olmanız gerekir. doğru. Birçoğu (şimdi) doğru davranıyor , ancak kontrol etmek önemlidir. Bunun nedeni, muhtemelen kullanmak istediğiniz Array.prototype yöntemlerinin çoğunun, ev sahibi tarafından sağlanan nesneye güvenmesidir, [[HasProperty]] dürüst bir cevap verin [[HasProperty]] . Bu yazının yazıldığı sırada, tarayıcılar bu konuda çok iyi bir iş çıkardılar, ancak 5.1 şartnamesi, ev sahibi tarafından sağlanan nesnenin adil olamayacağını öne sürdü. Bu, §8.6.2'de , bu bölümün başındaki büyük tablonun altındaki birkaç paragrafta yazılmıştır :

Ana bilgisayar nesneleri, bu dahili yöntemleri aksi belirtilmedikçe herhangi bir şekilde uygulayabilir; örneğin, bir olasılık, belirli bir ana bilgisayar nesnesi için [[Get]] ve [[Put]] aslında özellik değerlerini alması ve kaydetmesidir, ancak [[HasProperty]] her zaman yanlış üretir.

(ES2015 teknik özelliklerinde eşdeğer bir ifade bulamadım, ancak yine de olması gerekiyor.) Yine, modern tarayıcılarda sağlanan nesne türü dizisinin ortak bir ana bilgisayarını yazarken olduğu gibi [ NodeList örnekleri, [[HasProperty]] tutamacını doğru, ancak önemli [[HasProperty]] kontrol edin.)

6292
17 февр. Cevap TJ Crowder tarafından 17 Şubat'ta verildi. 2012-02-17 16:53 '12, 16:53, 2012-02-17 16:53

Düzenleme : Bu cevap umutsuzca eskidir. Daha modern bir yaklaşım için dizideki yöntemlere bakın. İlgilenilen yöntemler şunlar olabilir:

  • her biri için
  • harita
  • filtre
  • fermuar
  • azaltmak
  • her
  • biraz

Bir diziyi JavaScript'te yinelemenin standart yolu -loop vanilya'dır:

border=0
 var length = arr.length, element = null; for (var i = 0; i < length; i++) { element = arr[i]; // Do something with element } 

Bununla birlikte, bu yaklaşımın yalnızca yoğun bir diziniz varsa ve her bir dizin bir öğe tarafından işgal edildiğinde iyidir. Dizi seyrekse, o zaman bu yaklaşımla, gerçekte dizide bulunmayan birçok indeksden geçeceğiniz için performans sorunlarıyla karşılaşabilirsiniz. Bu durumda, -loop için kullanmak daha iyidir. Bununla birlikte, sadece gerekli dizilerin (yani, dizi öğelerinin) özelliklerinin etkin olduğundan emin olmak için uygun önlemleri kullanmanız gerekir, çünkü for -loop ayrıca eski tarayıcılarda da listelenir veya ek özellikler enumerable olarak tanımlanırsa.

ECMAScript 5'te , forEach yöntemi dizi prototipinde kullanılacak, ancak eski tarayıcılarda desteklenmiyor. Bu nedenle, sürekli olarak kullanabilmek için, onu destekleyen bir ortamınız olmalıdır (örneğin, sunucu tarafı JavaScript için Node.js ) veya "Polyfill" kullanın. Bununla birlikte, bu işlevsellik için Polyfill önemsizdir ve kodu okumayı kolaylaştırdığından, Polyfill'e dahil edilmelidir.

470
17 февр. 17 Şubat tarihinde PatrikAkerstrand tarafından verilen cevap . 2012-02-17 16:55 '12, 04:55, 2012-02-17 16:55

JQuery kütüphanesini kullanıyorsanız, jQuery.each öğesini kullanabilirsiniz:

 var length = yourArray.length; for (var i = 0; i < length; i++) { // Do something with yourArray[i]. } 
214
17 февр. Cevap Poonam 17 Şubat'ta verilir. 2012-02-17 17:01 '12, 17:01 2012-02-17 17:01

Geri döngü

Bence bu döngünün tam tersi burada bir sözü hakediyor:

 for (var i = array.length; i--; ) { // process array[i] } 

avantajları:

  • Bir geçici değişken len bildirmeniz veya her yinelemede array.length ile karşılaştırmanız array.length ; bu, dakika optimizasyonu olabilir.
  • DOM'den kardeşleri ters sırayla kaldırmak genellikle daha verimlidir . (Tarayıcının iç dizilerde daha az öğe taşıması gerekir.)
  • Bir döngü sırasında, bir indeks I'de veya sonrasında bir diziyi değiştirirseniz (örneğin, bir array[i] içine siler veya eklersiniz), o zaman doğrudan bir döngü, i konumuna getirmek için sola kaydırılan bir öğeyi atlar veya kaydırılan i-öğeyi yeniden kontrol eder. sağa doğru. Geleneksel döngüde, i'yi işlenmesi gereken bir sonraki öğeye işaret edecek şekilde güncelleyebilirsiniz - 1, ancak yinelemenin yönünü değiştirmek genellikle daha basit ve daha zarif bir çözümdür .
  • Benzer şekilde, iç içe DOM öğelerini değiştirirken veya silerken, ters işleme hataları atlayabilir . Örneğin, çocuklarını işlemeden önce ana düğümün içHTML'sini değiştirmeyi düşünün. Alt düğüme ulaşıldığında, ana innerHTML yazıldığında, onu yeni bir soydan değiştirerek DOM'dan ayrılır.
  • mevcut diğer seçeneklerden daha kısa ve okunabilir . Her şeyden önce forEach() ve for ... of için ES6'ya kaybeder.

dezavantajları:

  • Öğeleri ters sırada işler. Sonuçlardan yeni bir dizi oluşturduysanız veya ekrana yazdırdıysanız, çıktı elbette orijinal siparişe göre iptal edilir.
  • Неоднократно вставляя братьев и сестер в DOM в качестве первого ребенка, чтобы сохранить их порядок, менее эффективен . (В браузере все равно придется перекладывать вещи.) Чтобы создавать узлы DOM эффективно и упорядоченно, просто переходите вперед и добавьте как обычно (а также используйте "фрагмент документа" ).
  • Обратный цикл запутывает для младших разработчиков. (Вы можете считать это преимущество, в зависимости от вашего прогноза.)

Должен ли я всегда использовать его?