JavaScript'te bir dizi üzerinden her biri için


4682

JavaScript kullanarak bir dizideki tüm girişler arasında nasıl geçiş yapabilirim?

Bunun böyle bir şey olduğunu düşündüm:

forEach(instance in theArray)

Dizim nerede theArray, ama bu yanlış görünüyor.


16
Aradım, ama aradım forEach ve sadece değil for. belirtildiği gibi, c # biraz farklıydı ve bu beni
şaşırttı

6
ECMAScript & nbsp; 6 belki "for ... of" yapısını içerecektir. Bkz pazarına ... Daha fazla bilgi için (MDN). Son Firefox sürümleriyle zaten deneyebilirsiniz.
Slaven Rezic

36
Array.ForEach, JavaScript'teki Diziler için her biri için () öğesinden yaklaşık% 95 daha yavaştır. Bu performans testine çevrimiçi bakın: jsperf.com/fast-array-foreach via coderwall.com/p/kvzbpa
molokoloco

77

7
Buna karşılık, içinde Python öyle daha verimli döngüler için geleneksel kullanımına daha fonksiyonlarını kullanmak. (Bunu düşünün i < lenve i++tercüman tarafından değil, motor tarafından yapılabilir.)
joeytwiddle

Yanıtlar:


7021

TL; DR

  • Korumayla birlikte kullanmadıkça for-inveya en azından sizi neden ısırdığının farkında değilseniz kullanmayın.
  • En iyi bahisleriniz genellikle

    • bir for-ofdöngü (sadece ES2015 +),
    • Array#forEach( spec| MDN) (veya akrabaları somevb.) (yalnızca ES5 +),
    • basit bir eski moda fordöngü,
    • veya for-ingüvenlik önlemleri ile.

Ama keşfedilecek çok şey var , okumaya devam edin ...


JavaScript, diziler ve dizi benzeri nesneler arasında döngü yapmak için güçlü semantiğe sahiptir. Cevabı iki bölüme ayırdım : Orijinal diziler için seçenekler ve nesne, diğer yinelenebilir nesneler (ES2015 +), DOM koleksiyonları ve benzeri gibi sadece dizi benzeri şeyler için seçenekler arguments.

ES2015'i ES5'e aktararak , ES5 motorlarında bile şimdi ES2015 seçeneklerini kullanabileceğinizi hemen anlayacağım. Daha fazla bilgi için "ES2015 aktarma" / "ES6 aktarma" için arama ...

Tamam, seçeneklerimize bakalım:

Gerçek Diziler İçin

ECMAScript 5'te ("ES5") üç seçenek vardır , şu anda en yaygın olarak desteklenen sürüm ve ECMAScript 2015'e eklenmiş iki sürüm daha ("ES2015", "ES6"):

  1. Kullanım forEachve ilgili (ES5 +)
  2. Basit bir fordöngü kullanın
  3. Doğru kullanınfor-in
  4. Kullan for-of(üstü kapalı bir yineleyici kullan ) (ES2015 +)
  5. Açıkça yineleyici kullanma (ES2015 +)

Detaylar:

1. Kullanım forEachve ilgili

ArrayES5'in eklediği özelliklere (doğrudan veya çoklu dolgular kullanarak) erişebileceğiniz herhangi bir belirsiz modern ortamda (IE8 değil ), forEach( spec| MDN) kullanabilirsiniz :

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

forEachbir geri arama işlevini ve isteğe bağlı olarak, thisbu geri aramayı çağırırken kullanılacak bir değeri (yukarıda kullanılmaz) kabul eder. Seyir dizilerinde var olmayan girişleri atlamak için dizideki her giriş için geri arama çağrılır. Yukarıda yalnızca bir bağımsız değişken kullanmış olmama rağmen, geri çağrı üç ile çağrılır: Her girişin değeri, o girişin dizini ve yinelemekte olduğunuz diziye bir başvuru (işlevinizin zaten kullanışlı olmaması durumunda) ).

IE8 gibi eski tarayıcıları desteklemediğiniz sürece (NetApps Eylül 2016'da bu yazının% 4'ünden biraz fazla pazar payında gösterilir), forEachşim olmadan genel amaçlı bir web sayfasında mutlu bir şekilde kullanabilirsiniz . Eski tarayıcıları desteklemeniz gerekiyorsa, shimming / polyfilling forEachkolayca yapılabilir (çeşitli seçenekler için "es5 shim" araması yapın).

forEach , yineleme işlevine bağımsız değişkenler olarak sağlandıkları ve yalnızca bu yinelemenin kapsamı dahilinde olduğu için, dizin oluşturma ve değer değişkenlerini içeren kapsamda bildirmeniz gerekmemesi avantajına sahiptir.

Her dizi girişi için bir işlev çağrısı yapmanın çalışma zamanı maliyetinden endişe ediyorsanız, olmayın; ayrıntılar .

Buna ek forEacholarak, "hepsi arasında döngü" işlevi, ancak ES5 diğer birkaç yararlı "dizi boyunca yol ve bir şeyler yapmak" tanımlanmış tanımlanmıştır:

  • every(geri arama ilk kez döndüğünde falseveya sahte bir şey yapmayı durdurur )
  • some(geri arama ilk kez döndüğünde trueveya gerçeğe uygun bir şey yapmayı durdurur)
  • filter(filtre işlevinin geri döndüğü öğeleri içeren trueve geri döndüklerini içeren öğeleri içeren yeni bir dizi oluşturur false)
  • map (geri arama tarafından döndürülen değerlerden yeni bir dizi oluşturur)
  • reduce (önceki değerleri ileterek geri aramayı tekrar tekrar arayarak bir değer oluşturur; ayrıntılar için spesifikasyona bakın; bir dizinin içeriğini ve diğer birçok şeyi toplamak için yararlıdır)
  • reduceRight(gibi reduce, artan düzende değil azalan düzende çalışır)

2. Basit bir fordöngü 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]);
}

Dizinin uzunluğu döngü sırasında değişmeyecek ve (olası) performans duyarlı kodunda ise, ön uzunluğunu kapma biraz daha karmaşık sürümü olabilir küçücük biraz daha hızlı:

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

Ve / veya geriye doğru saymak:

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

Ancak modern JavaScript motorlarında, son meyve suyunu eklemeniz nadirdir.

ES2015 ve daha yeni sürümlerde, dizin ve değer değişkenlerinizi fordöngü için yerel yapabilirsiniz :

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

Bunu yaptığınızda, her döngü yinelemesi için değil, valueaynı zamanda indexyeniden oluşturulduğunda, döngü gövdesinde oluşturulan kapanmalar , söz konusu yineleme için oluşturulan index(ve value) referansı tutar :

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

Beş bölümünüz olsaydı, ilkini tıklarsanız "Dizin: 0" ve sonuncuyu tıkladıysanız "Dizin: 4" alırsınız. Bu mu değil kullanırsanız çalışmak varyerine let.

3. Doğru kullanınfor-in

Kullanmak söylüyorum insanları alırsınız for-in, ama bu değil ne for-iniçindir . for-indöngüsü bir nesnenin numaralandırılabilir özellikleri , bir dizi olup dizinler. Sipariş ES2015'te (ES6) bile garanti edilmez. ES2015 + nesne özelliklerinde bir emir tanımlamaz (aracılığıyla [[OwnPropertyKeys]], [[Enumerate]]ve bunları kullanmak şeyler gibi Object.getOwnPropertyKeys), ama o kadar tanımlamak vermedi for-inbu emri takip edecek; Yine de ES2020 yaptı. ( Bu diğer cevaptaki ayrıntılar .)

for-inBir dizideki gerçek kullanım durumları şunlardır:

  • Bu bir var seyrek diziler ile masif , içinde boşluklar veya
  • Eleman olmayan özellikleri kullanıyorsunuz ve bunları döngüye dahil etmek istiyorsunuz

Yalnızca ilk örneğe baktığımızda: for-inUygun önlemleri kullanıyorsanız, seyrek dizi öğelerini ziyaret etmek için kullanabilirsiniz:

// `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 checks are
        /^0$|^[1-9]\d*$/.test(key) &&    // explained
        key <= 4294967294                // below
        ) {
        console.log(a[key]);
    }
}

Üç kontrole dikkat edin:

  1. Nesnenin bu ada göre kendi özelliğine sahip olması (prototipinden miras aldığı değil) ve

  2. Anahtarın tüm ondalık basamaklar olması (ör. Bilimsel gösterim değil normal dize formu) ve

  3. Bir sayıya zorlandığında anahtarın değeri <= 2 ^ 32 - 2 (4,294,967,294). Bu sayı nereden geliyor? Bu , belirtimdeki bir dizi dizini tanımının bir parçasıdır . Diğer sayılar (tamsayı olmayanlar, negatif sayılar, 2 ^ 32 - 2'den büyük sayılar) dizi indeksleri değildir. Bunun 2 ^ 32 - 2 olmasının nedeni, en büyük dizin değerini , bir dizinin sahip olabileceği maksimum değer olan 2 ^ 32 - 1'den daha düşük hale getirmesidir length. (Örneğin, bir dizinin uzunluğu 32 bit işaretsiz bir tam sayıya sığar.) (Önceki yazımın tam olarak doğru olmadığını blog blogumdaki bir yorumda işaret ettiği için RobG'ye destek .)

Elbette bunu satır içi kodda yapmazsınız. Bir yardımcı program işlevi yazarsınız. Belki:

4. Kullanım for-of(dolaylı olarak yineleyici kullanın ) (ES2015 +)

ES2015 , JavaScript'e yineleyiciler ekledi . Yineleyicileri kullanmanın en kolay yolu yeni for-ofifadedir. Şöyle görünüyor:

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

Kapakların altında, diziden bir yineleyici alır ve içinden döngüler alır , değerleri alır. for-inNesne (dizi) tarafından tanımlanan bir yineleyici kullandığından ve diziler, yineleyicilerinin girdileri (özellikleri değil) aracılığıyla yinelediğini tanımladığı için, kullanımın sahip olduğu bir sorun yoktur. for-inES5'ten farklı olarak, girişlerin ziyaret edilme sırası dizinlerinin sayısal sırasıdır.

5. Açıkça bir yineleyici kullanın (ES2015 +)

Bazen, açıkça bir yineleyici kullanmak isteyebilirsiniz . Bunu da yapabilirsiniz, ancak çok daha karmaşıktır . Şöyle görünüyor:for-of

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

Yineleyici, belirtimdeki Yineleyici tanımıyla eşleşen bir nesnedir. Onun nextyöntemi, yeni bir döndürür sonuç nesnesi diyorsunuz her seferinde. Sonuç nesnesi, donebize yapılıp yapılmadığını söyleyen bir özelliğe valueve bu yinelemenin değerine sahip bir özelliğe sahiptir. ( doneolması isteğe bağlıdır false, valueolması isteğe bağlıdır undefined.)

Anlamı valueyineleyiciye bağlı olarak değişir; diziler yineleyicileri döndüren (en azından) üç işlevi destekler:

  • values(): Bu benim yukarıda kullandığım. Her bir yineleyici döndüren valuebu yineleme için dizi giriştir ( "a", "b"ve "c"örneğin daha önce).
  • keys(): Her birinin valueo yinelemenin anahtarı olduğu bir yineleyici döndürür (yani, ayukarıdaki için, o "0"zaman "1", o zaman "2").
  • entries(): Her birinin o yineleme valueiçin formdaki bir dizi olduğu bir yineleyici döndürür [key, value].

Dizi Benzeri Nesneler İçin

Gerçek dizilerin yanı sıra, sayısal adlara sahip bir özelliğe ve özelliklere sahip dizi benzeri nesneler de vardır length: NodeListörnekler, argumentsnesne, vb. İçerikleri arasında nasıl döngü oluştururuz?

Diziler için yukarıdaki seçeneklerden herhangi birini kullanın

Yukarıdaki dizi yaklaşımlarının en azından bazıları ve hatta çoğu veya hatta tümü, dizi benzeri nesnelere sıklıkla eşit derecede iyi uygulanır:

  1. Kullanım forEachve ilgili (ES5 +)

    Üzerindeki çeşitli işlevler Array.prototype"kasıtlı olarak genel" dir ve genellikle Function#callveya benzeri diziler gibi nesnelerde kullanılabilir Function#apply. ( Bu cevabın sonunda ana bilgisayar tarafından sağlanan nesneler için Caveat'a bakın , ancak bu nadir bir sorundur.)

    Kullanmak istediğim varsayalım forEachbir üzerinde Nodebireyin childNodesmülkiyet. Bunu yapardınız:

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

    Bunu çok yapacaksanız, işlev başvurusunun bir kopyasını yeniden kullanım için bir değişkene 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. Basit bir fordöngü kullanın

    Açıkçası, basit bir fordöngü dizi benzeri nesneler için geçerlidir.

  3. Doğru kullanınfor-in

    for-inbir dizi ile aynı güvenlik önlemleri ile dizi benzeri nesnelerle de çalışmalıdır; yukarıdaki # 1 üzerindeki ana bilgisayar tarafından sağlanan nesneler için uyarı geçerli olabilir.

  4. Kullan for-of(üstü kapalı bir yineleyici kullan ) (ES2015 +)

    for-ofkullanan yineleyici nesnesi (eğer varsa) ile yapılmalıdır. Ana bilgisayar tarafından sağlanan nesneleri içerir. Örneğin, NodeListfrom için teknik özellik querySelectorAllyinelemeyi destekleyecek şekilde güncellendi. HTMLCollectionKimden için spec getElementsByTagNamedeğildi.

  5. Açıkça yineleyici kullanma (ES2015 +)

    Bkz.

Gerçek bir dizi oluşturun

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

  1. sliceDiziler yöntemini kullanın

    sliceYukarıda belirtilen diğer yöntemler gibi "kasıtlı olarak genel" olan diziler yöntemini kullanabiliriz ve bu şekilde dizi benzeri nesnelerle kullanılabilir:

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

    Örneğin, a'yı NodeListgerçek bir diziye dönüştürmek istiyorsak , bunu yapabiliriz:

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

    Bkz konak tarafından sağlanan nesneler için ikaz altında. Özellikle, bunun IE8 ve önceki sürümlerinde başarısız olacağını ve bu şekilde ana bilgisayar tarafından sağlanan nesneleri kullanmanıza izin vermediğini unutmayın this.

  2. Forma sözdizimini kullan ( ...)

    ES2015'in yayılma sözdizimini bu özelliği destekleyen JavaScript motorlarıyla da kullanmak mümkündür . Gibi for-of, bu kullanır yineleyici nesnesi tarafından sağlanan (önceki bölümde 4. bakınız):

    var trueArray = [...iterableObject];

    Örneğin, a'yı NodeListgerçek bir diziye dönüştürmek istiyorsak , yayılım sözdizimi ile bu oldukça kısa ve öz olur:

    var divs = [...document.querySelectorAll("div")];
  3. kullanım Array.from

    Array.from (spec) | (MDN) (ES2015 +, ancak kolayca çok katmanlı), dizi benzeri bir nesneden bir dizi oluşturur ve isteğe bağlı olarak ilk önce girdileri bir eşleme işlevinden geçirir. Yani:

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

    Veya belirli bir sınıfa sahip öğelerin etiket adlarından oluşan bir dizi almak istiyorsanız, eşleme işlevini kullanırsınız:

    // 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 nesneler için uyarı

Eğer kullanırsanız Array.prototypeile işlevlerini konak tarafından sağlanan dizi benzeri (ziyade JavaScript motoru daha tarayıcı tarafından sağlanan DOM listeleri ve diğer şeyler) nesneler, emin konak tarafından sağlanan nesne davranır düzgün hale getirmek için hedef ortamlarında teste emin olmak gerekir . Çoğu (şimdi) düzgün davranıyor , ancak test etmek önemlidir. Bunun nedeni, Array.prototypekullanmak isteyeceğiniz yöntemlerin çoğunun , soyut [[HasProperty]]işlem için dürüst bir cevap veren ana bilgisayar tarafından sağlanan nesneye dayanmasıdır . Bu yazıdan itibaren, tarayıcılar bu konuda çok iyi bir iş çıkarıyor, ancak 5.1 spesifikasyonu, ana bilgisayar tarafından sağlanan bir nesnenin dürüst olmayabilir. Bu öyle §8.6.2 , diyor o bölümün başında), yakın büyük tablonun altındaki birkaç paragraflar:

Ana bilgisayar nesneleri, aksi belirtilmedikçe bu dahili yöntemleri herhangi bir şekilde uygulayabilir; örneğin, bir ihtimal olduğunu [[Get]]ve [[Put]]belirli bir konakçı nesnesi gerçekten de getirme ve mağaza özellik değerleri için değil, [[HasProperty]]hep oluşturur yanlış .

(Ben ES2015 spec eşdeğer şişirme bulamadık, ama yine de durum olacagi kesin.) Yine, ortak konak tarafından sağlanan [modern tarayıcılarda nesnelerin dizi benzeri bu yazının yazıldığı sırada NodeList, örneğin örnekleri] do sapı [[HasProperty]]doğru, ancak test etmek önemlidir.)


44
Ayrıca .forEachverimli bir şekilde kırılamayacağını da eklemek isterim . Ara vermek için bir istisna atmanız gerekiyor.
Pijusn

82
@Pius: Döngüyü kırmak istiyorsanız kullanabilirsiniz some. (Ben de kırmaya izin vermeyi tercih ederdim forEach, ama um, bana
sormadılar

6
@TJCrowder Doğru, asıl amacı olmadığı için daha çok bir çözüm gibi görünse de.
Pijusn

8
@ user889030: Bir ihtiyaç ,SONRA k=0değil, bir ;. Programlama detaya büyük önem bunlardan biri çok şey olduğunu unutmayın ... :-)
TJ Crowder

5
@JimB: Yukarıda ele alınmıştır (ve lengthbir yöntem değildir). :-)
TJ Crowder

513

Not : Bu cevap umutsuzca güncel değil. Daha modern bir yaklaşım için, bir dizideki mevcut yöntemlere bakın . İlgilenilen yöntemler şunlar olabilir:

  • her biri için
  • map
  • filtre
  • zip
  • azaltmak
  • her
  • biraz

JavaScript'te bir diziyi yinelemenin standart yolu vanilyalı bir fordöngüdür:

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 iyi olduğunu ve her dizinin bir öğe tarafından işgal edildiğini unutmayın. Dizi seyrek ise, bu yaklaşımla performans sorunlarıyla karşılaşabilirsiniz, çünkü dizide gerçekten bulunmayan birçok indeksi yineleyeceksiniz . Bu durumda, bir- for .. indöngü daha iyi bir fikir olabilir. Ancak , for..in-loop da eski tarayıcılarda numaralandırılacağından veya ek özelliklerin tanımlandığından enumerable.

In ECMAScript 5 dizi prototip üzerinde forEach yöntemi olacaktır, ancak eski tarayıcılarda desteklenmez. Bu nedenle, tutarlı bir şekilde kullanabilmek için, onu destekleyen bir ortamınız olması gerekir (örneğin, sunucu tarafı JavaScript için Node.js ) veya bir "Çoklu Dolgu" kullanmalısınız. Bununla birlikte, bu işlevsellik için Poli Dolgu önemsizdir ve kodun okunmasını kolaylaştırdığı için dahil edilmesi iyi bir poli doludur.


2
neden for(instance in objArray) doğru kullanım değil? benim için daha basit görünüyor, ama bunu doğru bir kullanım yolu olarak söylemediğinizi duyuyorum?
Dante1986

21
Satır içi uzunluk önbelleği kullanabilirsiniz: for (var i = 0, l = arr.length; i <l; i ++)
Robert Hoffmann

3
İlk satırın sonundaki virgül kasıtlı mı yoksa bir yazım hatası mı (noktalı virgül olabilir)?
Mohd Abdul Mujib

6
@ wardha-Web Kasıtlı. Tek bir varanahtar kelimeyle birden fazla değişken bildirmemizi sağlar . Noktalı virgül elementkullansaydık , o zaman küresel kapsamda ilan edilirdi (ya da daha doğrusu, JSHint üretime ulaşmadan önce bize çığlık atardı).
PatrikAkerstrand

239

JQuery kitaplığını kullanıyorsanız, jQuery.each kullanabilirsiniz :

$.each(yourArray, function(index, value) {
  // do your stuff here
});

DÜZENLE :

Soru başına, kullanıcı jquery yerine javascript kodu istiyor, böylece düzenleme

var length = yourArray.length;   
for (var i = 0; i < length; i++) {
  // Do something with yourArray[i].
}

2
Muhtemelen bu cevabı en sık kullanacağım. Bu sorunun en iyi yanıtı değildir, ancak pratikte jQuery kullananlarımız için en basit ve en uygulanabilir olanı olacaktır. Sanırım hepimiz vanilya yolunu da öğrenmeliyiz. Anlayışınızı genişletmek asla acıtmaz.
mopsyd

47
Sadece uğruna: jQuery her biri yerel çözümlerden çok daha yavaştır. JQuery tarafından mümkün olduğunda jQuery yerine yerel JavaScript kullanılması önerilir. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss

8
Vanilya js kullanırken jQuery kullanmaktan kaçının
Noe

2
Standart
JS'ye sadık kalın

116

Geriye doğru döngü yap

Bence döngü için ters bir söz hak ediyor:

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

Avantajları:

  • Geçici bir lendeğişken bildirmeniz veya array.lengthher yinelemede bunlarla karşılaştırmanız gerekmez; her ikisi de bir dakika optimizasyonu olabilir.
  • Kardeşleri DOM'dan ters sırayla kaldırmak genellikle daha etkilidir . (Tarayıcının dahili dizilerindeki öğelerin daha az kaydırılması gerekir.)
  • Eğer varsa dizi değiştirmek ya da dizin sonra, döngü sırasında i (örneğin, kaldırmak veya bir madde eklemek array[i]) sonra iletme döngüsü konuma doğru sola kaydırılmış madde atlamak i , ya da yeniden işlem i olarak inci madde sağa kaydı. Geleneksel bir döngüde, i'yi işlem gerektiren bir sonraki öğeye işaret edecek şekilde güncelleyebilirsiniz - 1, ancak yineleme yönünü tersine çevirmek genellikle daha basit ve daha zarif bir çözümdür .
  • Benzer şekilde, iç içe yerleştirilmiş DOM öğelerini değiştirirken veya kaldırırken , tersine işlem hataları önleyebilir . Örneğin, alt düğümünü işlemeden önce bir üst düğümün innerHTML'sini değiştirmeyi düşünün. Alt düğüme ulaşıldığında, ebeveynin innerHTML'si yazıldığında yeni oluşturulan bir çocuk ile değiştirilen DOM'dan ayrılacaktır.
  • Öyle kısa yazın ve okumaya müsait diğer seçeneklerden bazıları daha. forEach()ES6'lara ve ES6'lara kaybetmesine rağmen for ... of.

Dezavantajları:

  • Öğeleri ters sırada işler. Sonuçlardan yeni bir dizi oluşturuyorsanız veya ekranda bir şeyler yazdırıyorsanız , çıktı orijinal siparişe göre tersine çevrilir .
  • Siparişlerini korumak için kardeşleri DOM'a ilk çocuk olarak tekrar tekrar eklemek daha az verimlidir . (Tarayıcı her şeyi doğru kaydırmaya devam edecektir.) DOM düğümlerini verimli ve sırayla oluşturmak için, ileriye doğru döngü yapın ve normal olarak ekleyin (ve ayrıca bir "belge parçası" kullanın).
  • Ters döngü genç geliştiriciler için kafa karıştırıcı . (Görünümünüze bağlı olarak bunu bir avantaj olarak düşünebilirsiniz.)

Her zaman kullanmalı mıyım?

Bazı geliştiriciler, döngü için iyi bir neden olmadığı sürece, varsayılan olarak tersi için döngü kullanır .

Performans kazançları genellikle önemsiz olsa da, bir çeşit çığlık atıyor:

"Bunu listedeki her öğeye yap, sipariş umrumda değil!"

Ancak pratikte değil bunu yaparken bu vesilelerle ayırt edilemez olduğundan, aslında niyet güvenilir bir göstergesidir yapmak amacıyla ilgili bakım ve gerçekten yapmak ihtiyacını ters içinde döngü. Bu yüzden, aslında "umrumda değil" niyetini doğru bir şekilde ifade etmek için başka bir yapıya ihtiyaç duyulacaktır, ECMAScript dahil olmak üzere çoğu dilde mevcut olmayan ancak örneğin çağrılabilecek bir şey forEachUnordered().

Sipariş önemli değilse ve verimlilik bir endişe kaynağıysa (bir oyunun veya animasyon motorunun en içteki döngüsünde), döngü için tersi döngüyü go-to-patterniniz olarak kullanmak kabul edilebilir. Sadece mevcut kodda döngü için bir ters görmek mutlaka ilksiz anlamına gelmez unutmayın !

ForEach () kullanmak daha iyiydi

Genel olarak, netliğin ve güvenliğin daha fazla endişe duyduğu daha yüksek seviye kodu için , daha önce Array::forEachdöngü için varsayılan modeliniz olarak kullanılmasını önermiştim (bu günlerde kullanmayı tercih etsem de for..of). forEachTers bir döngü yerine tercih nedenleri :

  • Okumak daha açık.
  • Bu, i bloğun içinde kaydırılmayacağını gösterir (bu her zaman uzun forve whiledöngülerde saklanabilecek olası bir sürprizdir ).
  • Kapaklar için ücretsiz bir alan sağlar.
  • Yerel değişkenlerin sızmasını ve dış değişkenlerle kazayla çarpışmayı (ve mutasyona uğramasını) azaltır.

Kodunuzda döngü için tersini gördüğünüzde, bu iyi bir nedenden dolayı tersine çevrilmiş bir ipucudur (belki de yukarıda açıklanan nedenlerden biri). Ve döngü için geleneksel bir ileriye doğru gitmek, vites değiştirmenin gerçekleşebileceğini gösterebilir.

(Niyet tartışması sizin için bir anlam ifade etmiyorsa, siz ve kodunuz Crockford'un Programlama Stili ve Beyniniz hakkındaki dersini izlemekten faydalanabilirsiniz .)

Artık kullanmak için daha iyi .. of!

Olup olmadığı hakkında bir tartışma vardır for..ofya forEach()tercih edilir:

  • Maksimum tarayıcı desteği için, yineleyiciler for..of için bir çoklu dolgu gerektirir , bu da uygulamanızı yürütmek için biraz daha yavaş ve indirmek için biraz daha büyük olur.

  • Bu nedenle (ve kullanımını teşvik etmek mapve filter), bazı ön uç stil kılavuzları yasaklama for..oftamamen!

  • Ancak yukarıdaki endişeler for..of, artık iyi desteklenen Node.js uygulamaları için geçerli değildir .

  • Ve ayrıca içeride await çalışmazforEach() . Kullanımı for..ofise en açık desen bu durumda.

Kişisel olarak, performans veya küçültme büyük bir endişe haline gelmedikçe, okunması en kolay görünen şeyleri kullanma eğilimindeyim. Yani bugünlerde for..ofbunun yerine kullanmayı tercih ediyorum forEach(), ama her zaman mapya filterda findya someda uygulanabilir olduğunda kullanacağım . (Meslektaşlarım uğruna nadiren kullanıyorum reduce.)


O nasıl çalışır?

for (var i = 0; i < array.length; i++) { ... }   // Forwards

for (var i = array.length; i--; )    { ... }   // Reverse

i--Orta fıkra (genellikle bir karşılaştırma gördüğümüz yerde) ve son fıkra boş (genellikle gördüğümüz yerde) olduğunu fark edeceksiniz i++. Bu , devam i--etme koşulu olarak da kullanıldığı anlamına gelir . En önemlisi, her yinelemeden önce yürütülür ve kontrol edilir .

  • array.lengthPatlamadan nasıl başlayabilir ?

    Çünkü i--ishal önce her yineleme, birinci tekrar biz aslında öğeyi erişecek array.length - 1herhangi bir sorun kaçınan Dizi-out-of-sınırları undefined öğeler.

  • Neden dizin 0'dan önce yinelemeyi durdurmuyor?

    Koşul i--bir falsey değeri olarak değerlendirildiğinde döngü (0 değerini verdiğinde) yinelemeyi durduracaktır .

    Hile benzemez --i, arka i--operatör bir azalır iancak değerini verir önce azalmayla. Konsolunuz bunu gösterebilir:

    > var i = 5; [i, i--, i];

    [5, 5, 4]

    Bu yüzden son tekrarında, I , daha önce olduğu 1 ve i--sentezleme için değişir , 0 ama aslında verir 1 (truthy) ve durumu geçer, böylece. Bir sonraki yinelemede i , -1 olaraki-- değişir , ancak 0 (falsey) verir ve yürütmenin hemen döngünün altından düşmesine neden olur.

    Döngü için geleneksel ileri i++ve ++ideğiştirilebilir (Douglas Crockford'un işaret ettiği gibi). Ancak, döngünün tersi olarak, azalmamız aynı zamanda koşul ifademiz olduğu için, i--öğeyi dizin 0'da işlemek istiyorsak bağlı kalmalıyız .


önemsiz şeyler

Bazı insanlar ters fordöngüde küçük bir ok çizmeyi sever ve göz kırpma ile biter:

for (var i = array.length; i --> 0 ;) {

Krediler, döngü için tersinin faydalarını ve dehşetini göstermek için WYL'ye gidiyor.


3
Kıyaslamaları eklemeyi unuttum . Ayrıca, gerçekten ücretsiz karşılaştırmayı elde ettiğiniz 6502 gibi 8 bit işlemcilerde ters döngünün nasıl önemli bir optimizasyon olduğunu belirtmeyi unuttum!
joeytwiddle

Aynı cevap burada çok daha kısaca verilmiştir (farklı bir soru üzerine).
joeytwiddle

84

Bazı C stili diller foreachnumaralandırmalar arasında geçiş yapmak için kullanılır . JavaScript'te bu for..indöngü yapısı ile yapılır :

var index,
    value;
for (index in obj) {
    value = obj[index];
}

Bir av var. for..innesnenin numaralandırılabilir üyelerinin her biri ve prototipindeki üyeler arasında geçiş yapacaktır. Nesnenin prototipinden devralınan değerleri okumaktan kaçınmak için, özelliğin nesneye ait olup olmadığını kontrol edin:

for (i in obj) {
    if (obj.hasOwnProperty(i)) {
        //do stuff
    }
}

Ayrıca, ECMAScript 5 , bir calback kullanarak bir dizi üzerinde numaralandırmak için kullanılabilecek bir forEachyöntem ekledi Array.prototype(çoklu doldurma dokümanlar içindedir, böylece eski tarayıcılar için de kullanabilirsiniz):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

Array.prototype.forEachGeri arama geri döndüğünde kırılmadığını not etmek önemlidir false. jQuery ve Underscore.jseach kısa devre yapılabilen döngüler sağlamak için kendi varyasyonlarını sağlar.


3
Öyleyse, bir ECMAScript5 foreach döngüsünden normal bir for döngüsü veya C tarzı dillerde bulunan bir foreach döngüsü için nasıl kırılır?
Ciaran Gallagher

5
@CiaranG, JavaScript'te , döngüden çıkmak için kullanılmasına eachizin veren yöntemleri görmek yaygındır return false, ancak forEachbu bir seçenek değildir. Harici bir bayrak kullanılabilir (yani if (flag) return;, ancak işlev gövdesinin geri kalanının yürütülmesini engelleyecek, forEachyine de tüm koleksiyon üzerinde yinelemeye devam edecektir.
zzzzBov

43

Bir dizi üzerinde döngü yapmak istiyorsanız, standart üç parçalı fordöngüyü kullanın.

for (var i = 0; i < myArray.length; i++) {
    var arrayItem = myArray[i];
}

Önbelleğe alarak myArray.lengthveya geriye doğru yineleyerek bazı performans optimizasyonları alabilirsiniz .


6
(var i = 0, uzunluk = myArray.length; i <uzunluk; i ++) yapmalı
Edson Medina

5
@EdsonMedina Bu aynı zamanda yeni bir global değişken yaratacaktır length. ;)
joeytwiddle

4
@joeytwiddle Evet, ancak bu gönderinin kapsamı dışında. Yine de global bir i değişkeni yaratacaksınız.
Edson Medina

6
@EdsonMedina Özür dilerim, tamamen yanlış yaptım. Kullanımı ,bir görevden sonra yok değil Öneriniz sadece bu yüzden, yeni bir küresel tanıtmak ince ! Ben farklı bir sorun için bu kafa karıştırıcı: Kullanarak =bir görevden sonra ortaya çıkarmaz yeni küresel.
joeytwiddle

Dikkat i döngü için yerel değil . JavaScript'in blok kapsamı yoktur. var i, length, arrayItem;Bu yanlış anlaşılmayı önlemek için döngüden önce bildirmek daha iyidir .
James

35

Bunun eski bir gönderi olduğunu biliyorum ve zaten çok fazla harika cevap var. Biraz daha eksiksiz olmak için AngularJS kullanarak başka bir tane atacağım diye düşündüm . Tabii ki, bu sadece Angular kullanıyorsanız, elbette, yine de koymak istiyorum.

angular.forEach2 argüman ve isteğe bağlı bir üçüncü argüman alır. İlk bağımsız değişken, yinelenecek nesne (dizi), ikinci bağımsız değişken yineleyici işlevidir ve isteğe bağlı üçüncü bağımsız değişken ise nesne bağlamıdır (temelde döngü içinde 'this' olarak adlandırılır).

Açısal forEach döngüsünü kullanmanın farklı yolları vardır. En basit ve muhtemelen en çok kullanılan

var temp = [1, 2, 3];
angular.forEach(temp, function(item) {
    //item will be each element in the array
    //do something
});

Öğeleri bir diziden diğerine kopyalamak için kullanışlı bir başka yol da

var temp = [1, 2, 3];
var temp2 = [];
angular.forEach(temp, function(item) {
    this.push(item); //"this" refers to the array passed into the optional third parameter so, in this case, temp2.
}, temp2);

Bununla birlikte, bunu yapmak zorunda değilsiniz, sadece aşağıdakileri yapabilirsiniz ve önceki örneğe eşdeğerdir:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

Şimdi angular.forEach, vanilya aromalı fordöngüye göre işlevi kullanmanın artıları ve eksileri var .

Artıları

  • Kolay okunabilirlik
  • Kolay yazılabilirlik
  • Varsa angular.forEach, ES5 forEach döngüsünü kullanır. Şimdi, forEach döngüler for döngülerinden çok daha yavaş olduğu için eksiler bölümünde verimlilik elde edeceğim . Bunu bir profesyonel olarak belirtiyorum çünkü tutarlı ve standartlaştırılmış olmak güzel.

Aynı şeyi yapan aşağıdaki 2 iç içe döngüyü düşünün. Diyelim ki 2 nesne dizimiz var ve her nesne, her biri dize (ya da her neyse) olan bir Value özelliğine sahip bir dizi sonuç içeriyor. Ve diyelim ki sonuçların her birini tekrarlamalıyız ve eğer eşitlerlerse bazı eylemler gerçekleştirin:

angular.forEach(obj1.results, function(result1) {
    angular.forEach(obj2.results, function(result2) {
        if (result1.Value === result2.Value) {
            //do something
        }
    });
});

//exact same with a for loop
for (var i = 0; i < obj1.results.length; i++) {
    for (var j = 0; j < obj2.results.length; j++) {
        if (obj1.results[i].Value === obj2.results[j].Value) {
            //do something
        }
    }
}

Bu çok basit bir varsayımsal örnek, ancak ikinci yaklaşımı kullanarak döngüler için gömülü üçlü yazdım ve bu konuda okumak ve yazmak çok zordu.

Eksileri

  • Verimlilik. angular.forEach, ve doğal forEach, bu nedenle , her ikisi de normal fordöngüden çok daha yavaş .... yaklaşık % 90 daha yavaş . Büyük veri kümeleri için, yerelfor döngüye .
  • Ara vermek, devam etmek ya da destek vermek yok. continueaslında " kaza " tarafından desteklenir , angular.forEachbasit bir şekilde devam etmek için fonksiyonun içine bu yineleme için işlev dışında devam etmesine neden olacak bir return;ifade koymak angular.forEach(array, function(item) { if (someConditionIsTrue) return; });. Bunun nedeni yerli halkın forEachda ara vermeyi veya devam etmeyi desteklememesidir.

Eminim diğer çeşitli artıları ve eksileri de vardır ve lütfen uygun gördüğünüz herhangi birini eklemek için çekinmeyin. Sonuçta, verimliliğe ihtiyacınız varsa for, döngü ihtiyaçlarınız için sadece yerel döngü ile sopa olduğunu hissediyorum . Ancak, veri kümeleriniz daha küçükse ve okunabilirlik ve yazılabilirlik karşılığında vazgeçmek için bir miktar verimlilik varsa, o zaman elbette angular.forEacho kötü çocuğa atın .


34

Diziyi boşaltmanın sakıncası yoksa:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xöğesinin son değerini içerir yve diziden kaldırılır. Ayrıca shift()ilk öğeyi veren ve kaldıracak olan öğeyi kullanabilirsiniz y.


4
Gibi seyrek bir dizi olması durumunda işe yaramaz [1, 2, undefined, 3].
M.Grzywaczewski

2
... ya da gerçekten [1, 2, 0, 3][true, true, false, true]
falsey bir

31

Bir forEach uygulaması ( bkz. JsFiddle ):

function forEach(list,callback) {
  var length = list.length;
  for (var n = 0; n < length; n++) {
    callback.call(list[n]);
  }
}

var myArray = ['hello','world'];

forEach(
  myArray,
  function(){
    alert(this); // do something
  }
);

2
yineleyici, gereksiz uzunluk hesaplaması yapıyor. İdeal bir durumda, liste uzunluğu sadece bir kez hesaplanmalıdır.
MIdhun Krishna

2
@MIdhunKrishna Cevabımı ve jsFiddle'ı güncelledim ama düşündüğünüz kadar basit olmadığını unutmayın. Bu soruyu
nmoliveira

2
Tam ve doğru uygulama burada bulunabilir: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
marciowb

29

Muhtemelen for(i = 0; i < array.length; i++)döngü en iyi seçim değildir. Neden? Eğer buna sahipseniz:

var array = new Array();
array[1] = "Hello";
array[7] = "World";
array[11] = "!";

Yöntem, ile arasındaki çağrıyı array[0]yapar array[2]. Birincisi, bu ilk önce sahip olmadığınız değişkenlere referansta bulunur, ikincisi dizide değişkenlere sahip olmazsınız ve üçüncü olarak da kod daha kalın olur. Buraya bak, kullandığım şey:

for(var i in array){
    var el = array[i];
    //If you want 'i' to be INT just put parseInt(i)
    //Do something with el
}

Ve bir işlev olmasını istiyorsanız, bunu yapabilirsiniz:

function foreach(array, call){
    for(var i in array){
        call(array[i]);
    }
}

Eğer kırmak istiyorsanız, biraz daha mantık:

function foreach(array, call){
    for(var i in array){
        if(call(array[i]) == false){
            break;
        }
    }
}

Misal:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Döndürür:

//Hello
//World
//!!!

29

Üç uygulamaları vardır foreachiçinde jQuery olarak izler.

var a = [3,2];

$(a).each(function(){console.log(this.valueOf())}); //Method 1
$.each(a, function(){console.log(this.valueOf())}); //Method 2
$.each($(a), function(){console.log(this.valueOf())}); //Method 3

2
Konsol günlüğü sadece demo içindir. Bu onu tam çalışan bir örnek yapmak.
Rajesh Paul

29

ECMAScript 6 itibariyle:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

Nerede ofilişkili garipliklerden kaçınır ve başka bir dilin döngüsü ingibi çalışır forve letbağlanıri işlev içinde karşıt olarak döngü içinde.

Parantez ( {}) yalnızca bir komut olduğunda atlanabilir (örn. Yukarıdaki örnekte).


28

Artık kolay bir çözüm underscore.js kütüphanesini kullanmak olacaktır . Gibi birçok yararlı araç sağlar eachve forEachvarsa işi otomatik olarak yerel kişiye devreder .

Nasıl çalıştığına dair bir CodePen örneği :

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

Ayrıca bakınız


23

for eachYerel JavaScript'te döngü yok . Bu işlevselliği almak için kütüphaneleri kullanabilirsiniz ( Underscore.js'yi öneriyorum ), basit bir fordöngü kullanın .

for (var instance in objects) {
   ...
}

Ancak, daha basit bir fordöngü kullanmak için nedenler olabileceğini unutmayın (bkz. Yığın Taşması sorusu Neden dizi yinelemesinde “for… in” kullanılıyor? Bu kadar kötü bir fikir? )

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}

22

Bu, endeksin 0'da başladığı seyrek olmayan liste için bir yineleyicidir; bu, document.getElementsByTagName veya document.querySelectorAll ile uğraşırken tipik bir senaryodur)

function each( fn, data ) {

    if(typeof fn == 'string')
        eval('fn = function(data, i){' + fn + '}');

    for(var i=0, L=this.length; i < L; i++) 
        fn.call( this[i], data, i );   

    return this;
}

Array.prototype.each = each;  

Kullanım örnekleri:

Örnek 1

var arr = [];
[1, 2, 3].each( function(a){ a.push( this * this}, arr);
arr = [1, 4, 9]

Örnek 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Her p etiketi class="blue"

Örnek 3

each.call(document.getElementsByTagName('p'), 
    "if( i % 2 == 0) this.className = data;",
    'red'
);

Diğer her p etiketi class="red">

Örnek 4 -

each.call(document.querySelectorAll('p.blue'), 
    function(newClass, i) {
        if( i < 20 )
            this.className = newClass;
    }, 'green'
);

Ve son olarak ilk 20 mavi p etiketi yeşile değiştirildi

Dizeyi işlev olarak kullanırken dikkat edin: işlev bağlam dışında oluşturulur ve yalnızca değişken kapsam belirlemesinden emin olduğunuz yerlerde kullanılmalıdır. Aksi takdirde, kapsam belirleme işleminin daha sezgisel olduğu durumlarda işlevleri geçmek daha iyidir.


21

Aşağıdaki gibi JavaScript'te bir dizi arasında geçiş yapmanın birkaç yolu vardır :

çünkü - en yaygın olanıdır . Döngü için tam kod bloğu

var languages = ["Java", "JavaScript", "C#", "Python"];
var i, len, text;
for (i = 0, len = languages.length, text = ""; i < len; i++) {
    text += languages[i] + "<br>";
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

while - döngü sırasında bir koşul. En hızlı döngü gibi görünüyor

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while - koşul doğruyken bir kod bloğunda da döngü yapar, en az bir kez çalışır

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

Fonksiyonel döngüler - forEach, map, filter, ayrıca reducesen vb dizisi, bir şeyler yapmak gerekiyorsa (kişilermişiz işlevi aracılığıyla döngü, ancak kullanıldıkları

// For example, in this case we loop through the number and double them up using the map function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

Dizilerde işlevsel programlama hakkında daha fazla bilgi ve örnek için JavaScript'teki işlevsel programlama: harita, filtreleme ve azaltma başlıklı blog yazısına bakın .


Küçük düzeltme: forEach"işlevsel" bir döngü değildir, çünkü yeni döndürmez Array(aslında hiçbir şey döndürmez), sadece yineler.
nicholaswmin

19

Dizilerle çalışmak için ECMAScript 5 (JavaScript sürümü):

forEach - Dizideki her öğeyi yineler ve her öğeyle ihtiyacınız olanı yapar.

['C', 'D', 'E'].forEach(function(element, index) {
  console.log(element + " is #" + (index+1) + " in the musical scale");
});

// Output
// C is the #1 in musical scale
// D is the #2 in musical scale
// E is the #3 in musical scale

Durumda, bazı dahili özelliği kullanarak dizi üzerinde daha fazla ilgilenmek.

map - Geri arama işlevinin sonucu ile yeni bir dizi oluşturur. Dizinizin öğelerini biçimlendirmeniz gerektiğinde bu yöntem kullanmak iyidir.

// Let's upper case the items in the array
['bob', 'joe', 'jen'].map(function(elem) {
  return elem.toUpperCase();
});

// Output: ['BOB', 'JOE', 'JEN']

reduce - Adından da anlaşılacağı gibi, geçerli öğeden geçen verilen işlevi ve önceki yürütmenin sonucunu çağırarak diziyi tek bir değere düşürür.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - Dizideki tüm öğeler testi geri arama işlevinde geçerse true veya false değerini döndürür.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter - Filtre, verilen işleve true döndüren öğelerin bulunduğu bir dizi döndürmesi dışında herkese çok benzer.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

16

İçeri girme yeteneği yok forEach. Yürütmeyi kesmek için Array#someaşağıdakini kullanın :

[1,2,3].some(function(number) {
    return number === 1;
});

Bunun nedeni some, dizi sırasına göre yürütülen geri aramalardan herhangi biri, geri dönmenin yürütülmesini kısa devre yapan true değerini döndürdüğü için true değerini döndürdüğü için çalışır . Orijinal Yanıt Bazıları için Array prototipine bakın


13

Ayrıca bu sözdizimini de isteyen biri için bir ters döngü ve yukarıdaki bir cevap bileşimi olarak eklemek istiyorum.

var foo = [object,object,object];
for (var i = foo.length, item; item = foo[--i];) {
    console.log(item);
}

Artıları:

Bunun yararı: Daha önce başka bir satırla bildirilmesi gerekmeyecek şekilde, ilk başta referansınız var. Nesne dizisinde döngü yaparken kullanışlıdır.

Eksileri:

Bu, referans yanlış olduğunda (kırılmaz) tanımlanmayacaktır. Yine de bir avantaj olarak kullanılabilir. Ancak, okumayı biraz zorlaştırır. Ve ayrıca tarayıcıya bağlı olarak orijinal olandan daha hızlı çalışmak için optimize edilemez.


12

jQuery yolu kullanarak $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

1
Bence çıktı daha muhtemel [undefined, 2, undefined, 4, undefined, 6, undefined].

10

ECMAScript 6 imhası ve spread operatörü ile döngüler kullanma

Forma operatörünün yıkımı ve kullanımının ECMAScript 6'ya yeni gelenler için daha insan tarafından okunabilir / estetik olduğu için oldukça yararlı olduğu kanıtlanmıştır, ancak bazı JavaScript gazileri dağınık olarak düşünebilir. Gençler veya bazı insanlar bunu faydalı bulabilir.

Aşağıdaki örnekler for...ofifade ve .forEachyöntemi kullanacaktır .

Örnekler 6, 7 ve 8 gibi herhangi bir işlevsel döngüler ile birlikte kullanılabilir .map, .filter, .reduce, .sort, .every, .some. Bu yöntemler hakkında daha fazla bilgi için Dizi Nesnesi'ne bakın .

Örnek 1: Normal for...ofdöngü - burada hile yok.

let arrSimple = ['a', 'b', 'c'];

for (let letter of arrSimple) {
  console.log(letter);
}

Örnek 2: Kelimeleri karakterlere bölme

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Örnek 3: a keyvevalue

// let arrSimple = ['a', 'b', 'c'];

// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`
// this example will use a multi-dimensional array of the following format type:
// `arrWithIndex: [number, string][]`

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Same thing can be achieved using `.map` method
// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);

// Same thing can be achieved using `Object.entries`
// NOTE: `Object.entries` method doesn't work on Internet Explorer  unless it's polyfilled
// let arrWithIndex = Object.entries(arrSimple);

for (let [key, value] of arrWithIndex) {
  console.log(key, value);
}

Örnek 4: Nesne özelliklerini yerinde alma

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Örnek 5: İhtiyacınız olan şeyin derin nesne özelliklerini edinin

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Örnek 6: Is Örnek 3 ile kullanılan.forEach

let arrWithIndex = [
  [0, 'a'],
  [1, 'b'],
  [2, 'c'],
];

// Not to be confused here, `forEachIndex` is the real index
// `mappedIndex` was created by "another user", so you can't really trust it

arrWithIndex.forEach(([mappedIndex, item], forEachIndex) => {
  console.log(forEachIndex, mappedIndex, item);
});

Örnek 7: Örnek 4 aşağıdakilerle birlikte mi kullanılıyor?.forEach

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];
// NOTE: Destructuring objects while using shorthand functions
// are required to be surrounded by parentheses
arrWithObjects.forEach( ({ name, age: aliasForAge }) => {
  console.log(name, aliasForAge)
});

Örnek 8: Is Örnek 5 ile kullanılan.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


7

Fikrinize en yakın yol Array.forEach(), dizinin her bir öğesi için yürütülecek bir kapatma işlevini kabul eden bir yöntem olacaktır.

myArray.forEach(
  (item) => {
    // Do something
    console.log(item);
  }
);

Başka bir geçerli yol da Array.map()aynı şekilde çalışan kullanmaktır , ancak döndürdüğünüz tüm değerleri alır ve bunları yeni bir dizide döndürür (esas olarak her öğeyi yenisiyle eşleştirir), örneğin:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

1
Bu yanlıştır, mapdizinin öğelerini değiştirmez, çünkü yeni diziyi döndürür, yeni dizinin öğeleri işlevi eski dizinin öğelerine uygulamanın sonucudur.
Jesús Franco

Yeni bir dizi döndürmediğini söylemedim, fonksiyon tarafından uygulanan değişikliğe atıfta bulundum. Ama burada cevabı değiştireceğim.
Ante Jablan Adamović

yine yanlış, harita orijinal dizideki tüm öğeleri değiştirmez veya değiştirmez, önerdiğim ve haritanın orijinal öğelerin bir kopyasıyla çalıştığını vurgulayarak yanıtı düzenledim , orijinal diziye hiç dokunulmadı
Jesús Franco

7

ForEach'ı şu şekilde arayabilirsiniz:

forEachsağladığınız dizi üzerinden yineleme yapar ve her yineleme için element, bu yinelemenin değerini tutan sahip olur. Dizine ihtiyacınız varsa iforEach için geri arama işlevinde ikinci parametre olarak ileterek geçerli dizini alabilirsiniz .

Foreach, temel olarak, parametre olarak başka bir işlevi alan bir Yüksek Sipariş İşlevidir.

let theArray= [1,3,2];

theArray.forEach((element) => {
  // Use the element of the array
  console.log(element)
}

Çıktı:

1
3
2

Ayrıca böyle bir dizi üzerinden yineleme yapabilirsiniz:

for (let i=0; i<theArray.length; i++) {
  console.log(i); // i will have the value of each index
}

6

Ok işleviyle bir nesne dizisi arasında döngü yapmak istiyorsanız:

let arr = [{name:'john', age:50}, {name:'clark', age:19}, {name:'mohan', age:26}];

arr.forEach((person)=>{
  console.log('I am ' + person.name + ' and I am ' + person.age + ' old');
})


6

Lambda sözdizimi genellikle Internet Explorer 10 veya daha eski sürümlerinde çalışmaz.

Ben genellikle

[].forEach.call(arrayName,function(value,index){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

Bir jQuery hayranıysanız ve zaten çalışan bir jQuery dosyanız varsa, dizin ve değer parametrelerinin konumlarını tersine çevirmelisiniz

$("#ul>li").each(function(**index, value**){
    console.log("value of the looped element" + value);
    console.log("index of the looped element" + index);
});

5

Büyük bir diziniz varsa, iteratorsbiraz verimlilik elde etmek için kullanmalısınız . Tekrarlayıcılar belirli JavaScript koleksiyonlarından bir malıdır (gibi Map, Set, String, Array). Hatta, kaputun altında for..ofkullanır iterator.

Yineleyiciler, listedeki öğeleri birer birer akış gibi tüketmenize izin vererek verimliliği artırır. Bir yineleyiciyi özel yapan şey, bir koleksiyonu nasıl geçtiğidir. Diğer döngülerin, yinelemek için tüm koleksiyonu önden yüklemesi gerekirken, yineleyicinin yalnızca koleksiyondaki geçerli konumu bilmesi gerekir.

Geçerli öğeye yineleyicinin nextyöntemini çağırarak erişirsiniz . Bir sonraki yöntem value, geçerli öğeyi döndürür booleanve koleksiyonun ne zaman sona erdiğini belirtmek için a değerini döndürür . Aşağıda, bir diziden yineleyici oluşturmaya bir örnek verilmiştir.

Aşağıdaki values()gibi bir yöntem kullanarak normal dizinizi yineleyiciye dönüştürün :

    const myArr = [2,3,4]

let it = myArr.values();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Normal dizinizi şu şekilde kullanarak yineleyiciye de dönüştürebilirsiniz Symbol.iterator:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Ayrıca normalinizi buna benzer arraybir şekilde dönüştürebilirsiniz iterator:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

NOT :

  • Yineleyiciler doğada tüketilebilir.
  • Nesneler iterablevarsayılan olarak değildir . Kullanım for..inyerine değerlerin o anahtarlarıyla çalışır çünkü bu durumda.

iteration protocol Burada daha fazla bilgi edinebilirsiniz .


5

Kullanmak istiyorsanız forEach(), şöyle görünecektir -

theArray.forEach ( element => {
    console.log(element);
});

Kullanmak istiyorsanız for(), şöyle görünecektir -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

4

ECMAScript 6 (ES6) ve ECMAScript 2015'in yeni güncellenmiş özelliğine göre, aşağıdaki seçenekleri döngülerle kullanabilirsiniz:

döngüler için

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

için ... döngülerde

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach ()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

döngüler için

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

döngülerken

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

yap ... döngüler yaparken

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

4

Verim

Bugün (2019/12/18) Benim testi uygulayarak MacOS v10.13.6 Krom v 79.0 üzerinde, (High Sierra), Safari v13.0.4 ve Firefox v71.0 (64 bit) - optimizasyonu hakkında sonuçlar (ve mikro optimizasyonu hangi genellikle kod için tanıtmaya değmez, çünkü fayda küçüktür, ancak kod karmaşıklığı büyür).

  • Geleneksel for i( Aa ) tüm tarayıcılarda hızlı kod yazmak için iyi bir seçim gibi görünüyor .

  • Gibi diğer çözümler, for-of( Reklam grubu olarak), tüm C ... genelde 2 şunlardır - 10 (ve daha fazla) daha yavaş kez Aa , ama küçük diziler için onu kullanmak için ok - artış kod netlik uğruna.

  • Dizi uzunluğu önbelleğe alınan döngüler n( Ab, Bb, Be ) bazen daha hızlı, bazen değil. Muhtemelen derleyiciler bu durumu otomatik olarak algılar ve önbelleğe alır. Önbelleğe alınmış ve önbelleğe alınmamış sürümler ( Aa, Ba, Bd ) arasındaki hız farkları yaklaşık ~% 1'dir, bu yüzden tanıtmak nbir mikro optimizasyon gibi görünüyor .

  • i--Geçen dizi öğesi (dan döngü başlar çözümleri gibi Ac, Bc muhtemelen nedeni yoludur -) ileri çözümlerine kıyasla genelde ~% 30 daha yavaş olan CPU önbellek çalışma - İleri bellek okuma işlemci önbelleğe alma için daha iyi) 'dir. Bu tür çözümleri KULLANMAMANIZ önerilir.

ayrıntılar

Testlerde dizi elemanlarının toplamını hesaplıyoruz. Küçük diziler (10 element) ve büyük diziler (1M elementler) için bir test yapıyorum ve bunları üç gruba ayırıyorum:

  • A - fortestler
  • B - whiletestler
  • C - diğer / alternatif yöntemler

Çapraz tarayıcı sonuçları

Test edilen tüm tarayıcılar için sonuçlar

Resim açıklamasını buraya girintarayıcılar **

10 elemanlı dizi

Chrome sonuçları. Testi makinenizde buradan yapabilirsiniz .

Resim açıklamasını buraya girin

1.000.000 element içeren dizi

Chrome sonuçları. Testi makinenizde buradan yapabilirsiniz

Resim açıklamasını buraya girin


4

Özet:

Bir dizi üzerinden yineleme yaparken, genellikle aşağıdaki hedeflerden birini gerçekleştirmek isteriz:

  1. Dizi üzerinde yineleme yapmak ve yeni bir dizi oluşturmak istiyoruz:

    Array.prototype.map

  2. Dizi üzerinde yineleme yapmak istiyoruz ve yeni bir dizi oluşturmuyoruz:

    Array.prototype.forEach

    for..of döngü

JavaScript'te, bu hedeflerin her ikisini de gerçekleştirmenin birçok yolu vardır. Ancak, bazıları diğerlerinden daha uygundur. Aşağıda JavaScript'te dizi yinelemesini gerçekleştirmek için yaygın olarak kullanılan bazı yöntemleri (en uygun IMO) bulabilirsiniz.

Yeni dizi oluşturuluyor: Map

map(), bir Array.prototypedizinin her öğesini dönüştürebilen ve sonra yeni bir dizi döndüren bir işlevdir . map()bağımsız değişken olarak geri çağrı işlevini alır ve aşağıdaki şekilde çalışır:

let arr = [1, 2, 3, 4, 5];

let newArr = arr.map((element, index, array) => {
  return element * 2;
})

console.log(arr);
console.log(newArr);

Bağımsız map()değişken olarak aktardığımız geri arama her öğe için yürütülür. Ardından orijinal diziyle aynı uzunlukta bir dizi döndürülür. Bu yeni dizi öğesinde bir argüman olarak geçirilen geri çağrı fonksiyonu tarafından dönüştürülürmap() .

Arasında belirgin bir fark mapve benzeri gibi başka bir döngü mekanizması forEachve bir for..ofhalka olmasıdır mapdöndürür yeni bir dizi ve yapraklar durumdaki eski dizi (gibi düşünen ile açıkça işlemek durumu hariç splice).

Ayrıca, mapişlevin geri aramasının geçerli yinelemenin dizin numarasını ikinci bir bağımsız değişken olarak sağladığını unutmayın . Ayrıca, üçüncü argüman mapçağrılan diziyi sağlıyor mu? Bazen bu özellikler çok faydalı olabilir.

Kullanarak döngü forEach

forEachbulunan bir fonksiyonu olan Array.prototypebir değişken olarak bir geri arama işlevi alır. Daha sonra dizideki her öğe için bu geri çağırma işlevini yürütür. map()İşlevin aksine , forEach işlevi hiçbir şey döndürmez ( undefined). Örneğin:

let arr = [1, 2, 3, 4, 5];

arr.forEach((element, index, array) => {

  console.log(element * 2);

  if (index === 4) {
    console.log(array)
  }
  // index, and oldArray are provided as 2nd and 3th argument by the callback

})

console.log(arr);

mapİşlev gibi, forEachgeri arama da geçerli yinelemenin dizin numarasını ikinci bir bağımsız değişken olarak sağlar. Ayrıca, üçüncü argüman forEachçağrılan diziyi sağlıyor mu?

Elemanları kullanarak döngü yap for..of

for..ofDöngü bir dizi (ya da başka bir iterable nesnenin) her elemanın döngüsü. Aşağıdaki şekilde çalışır:

let arr = [1, 2, 3, 4, 5];

for(let element of arr) {
  console.log(element * 2);
}

Yukarıdaki örnekte, elementbir dizi öğesi anlamına gelir ve arrdöngü yapmak istediğimiz dizidir. Adınelement isteğe bağlı 'el' gibi başka bir ad veya uygulanabilir olduğunda daha açıklayıcı bir şey seçmiş olabileceğimizi unutmayın.

for..inDöngüyü döngü ile karıştırmayın for..of. for..indizi for..ofyalnızca dizi öğeleri arasında döngü yaparken, dizi tüm numaralandırılabilir özellikleri arasında döngü. Örneğin:

let arr = [1, 2, 3, 4, 5];

arr.foo = 'foo';

for(let element of arr) {
  console.log(element);
}

for(let element in arr) {
  console.log(element);
}

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.