Soru JavaScript'te her bir dizi için?


JavaScript kullanarak bir dizideki tüm girişleri nasıl kullanabilirim?

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

forEach(instance in theArray)

Nerede theArray dizim, ama bu yanlış gibi görünüyor.


3791
2018-02-17 13:51


Menşei


Onu aradım ama aradım forEach  ve sadece değil for. belirtildiği gibi, c # biraz farklıydı ve bu beni şaşırttı :) - Dante1986
ECMAScript & nbsp; 6, "for" için "yapı" içerebilir. Görmek Türk pazarına ... Daha fazla bilgi için (MDN). Son Firefox sürümleriyle zaten deneyebilirsiniz. - Slaven Rezic
Array.ForEach, JavaScript'teki Diziler için her biri için () inden yaklaşık% 95 daha yavaştır. Bu performans testine çevrimiçi bakın: jsperf.com/fast-array-foreach üzerinden coderwall.com/p/kvzbpa - molokoloco
Birçok durum için% 95 daha yavaş olan önemli olmayacaktır. blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html - David Sykes
Buna karşın, piton bu daha verimli Fonksiyonları kullanmak için döngüler için geleneksel kullanmadan. (Bunu bir düşün i < len ve i++ tercüman tarafından değil, motor tarafından yapılabilir.) - joeytwiddle


Cevaplar:


TL; DR

  • Kullanma for-in bunu korumalarla kullanmazsanız veya en azından sizi neden ısırdığının farkında değilsiniz.
  • En iyi bahisleriniz genellikle

    • bir for-of döngü (yalnızca ES2015 +),
    • Array#forEach (spec | MDN) (veya akrabaları) some ve böyle) (sadece ES5 +),
    • basit bir eski moda for döngü,
    • veya for-in korumaları ile.

Ama orada çok Keşfetmek, okumak için ...


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

Hızlıca ES2015 seçeneklerini kullanabileceğinizi not edeceğim şimdiES5 motorlarda bile transpiling ES2015 ila ES5. Daha fazla bilgi için "ES2015 transpiling" / "ES6 transpiling" araması yapın ...

Tamam, seçeneklere bakalım:

Fiili Diziler İçin

İçinde üç seçeneğiniz var ECMAScript 5 ("ES5"), şu anda en çok desteklenen sürüm ve iki tane daha eklendi ECMAScript 2015 ("ES2015", "ES6"):

  1. kullanım forEach ve ilgili (ES5 +)
  2. Basit kullan for döngü
  3. kullanım for-in  doğru şekilde
  4. kullanım for-of (örtülü bir yineleyici kullanın) (ES2015 +)
  5. Açık bir yineleyici kullanın (ES2015 +)

Detaylar:

1. Kullanım forEach ve ilgili

Herhangi bir belirsiz-modern ortamda (yani IE8 değil) Array ES5 tarafından eklenen özellikler (doğrudan veya polyfills kullanarak), kullanabilirsiniz forEach (spec | MDN):

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, aşağıdaki gibi kullanılacak bir değeri kabul eder. this Bu geri arama çağrıldığında (yukarıda kullanılmamaktadır). Dizideki her giriş için, sıralı olmayan dizilerdeki var olmayan girişleri atlamak için geri arama çağrılır. Yukarıda yalnızca bir argüman kullanmış olmama rağmen, geri arama üç ile çağrılır: Her bir girişin değeri, o girdinin indeksi ve yineleme yaptığınız diziye yapılan bir referans (işlevinizin zaten kullanışlı olmaması durumunda) ).

IE8 gibi eski olmayan tarayıcıları desteklemediğiniz sürece (NetApps, Eylül 2016'da bu yazının% 4'ünde pazar payını gösterir) mutlu bir şekilde kullanabilirsiniz. forEach Şimasız genel amaçlı bir web sayfasında. Eski tarayıcıları desteklemeniz gerekiyorsa, shimming / polyfilling forEach kolayca yapılır (çeşitli seçenekler için "es5 shim" araması yapın).

forEach Yineleme işlevine argümanlar olarak sağlandıklarından ve bu yineleme için çok iyi bir şekilde belirtildiklerinden, içerme dizininde indeksleme ve değer değişkenlerini bildirmeniz gerekmediğinden yararlanır.

Her dizi girişi için bir işlev çağrısı yapmak için çalışma zamanı maliyeti konusunda endişeleniyorsanız; ayrıntılar.

Bunlara ek olarak, forEach "hepsi aracılığıyla döngü" işlevi, ancak ES5 de dahil olmak üzere birkaç diğer yararlı "dizi ve iş şeyler yapmak" işlevlerini tanımladı:

  • every (geri dönüş ilk kez dönmeyi durdurur false ya da bir şey falsey)
  • some (geri dönüş ilk kez dönmeyi durdurur true ya da gerçek bir şey)
  • filter (Filtre işlevinin döndüğü öğeleri içeren yeni bir dizi oluşturur true ve döndüğü yerlerin ihmal edilmesi false)
  • map (geri arama tarafından döndürülen değerlerden yeni bir dizi oluşturur)
  • reduce (geri aramaları tekrar tekrar arayarak, önceki değerlerden geçerek 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 kullanışlıdır)
  • reduceRight (sevmek reduceama artan sırada değil, azalan şekilde çalışır.

2. Basit kullanın for döngü

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şmezse ve performansa duyarlı kodda (olası değilse), uzunluğu ön tarafa çeken biraz daha karmaşık bir sürüm olabilir. minik 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 sayma:

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

Ancak modern JavaScript motorları ile, bu son meyve suyu parçasını çıkarmak için gerek duyduğunuz nadirdir.

ES2015 ve sonraki sürümlerde, indeks ve değer değişkenlerinizi yerel for döngü:

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 Ayrıca index her döngü yinelemesi için yeniden oluşturulur, yani döngü gövdesinde oluşturulan kapanışların anlamı index (ve value) Bu spesifik yineleme için oluşturuldu:

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

Beş diviniz varsa, ilkini tıkladıysanız ve son tıkladıysanız "Dizin: 4" ise "Dizin: 0" olur. Bu yapar değil kullanırsan çalışırsın var yerine let.

3. kullanın for-in  doğru şekilde

Kullanmanız gerektiğini söyleyen kullanıcılara sahip olacaksınız for-in, fakat bu ne değil for-in için. for-in aracılığıyla döngüler bir nesnenin sayısız özellikleribir dizinin dizinleri değil. Sipariş garanti edilmezES2015'te (ES6) bile değil. ES2015, özelliklerin nesneye gönderilmesi için bir sıralama tanımlar [[OwnPropertyKeys]], [[Enumerate]]ve onları gibi kullanan şeyler Object.getOwnPropertyKeys), ama o değil bunu tanımla for-in bu emri takip edecek. (Ayrıntılar bu diğer cevap.)

Yine de kutu özellikle yararlı olmak seyrek dizilerEğer uygun önlemleri kullanırsanız:

// `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. Bu nesnenin kendi Bu isme göre (prototipinden miras alan değil)

  2. Anahtar, normal dize biçiminde bir taban-10 sayısal dizesi ve değeri <= 2 ^ 32 - 2'dir (4,294,967,294). Bu numara nereden geliyor? Dizi dizininin tanımının bir parçası şartnamede. Diğer sayılar (tamsayılar, negatif sayılar, 2 ^ 32 - 2'den büyük sayılar) dizi dizinleri değildir. Nedeni 2 ^ 32 - 2 Bu en büyük endeks değerini 2 ^ 32'den düşük yapan 1Bir dizinin maksimum değeri olan length sahip olabilmek. (Ör: bir dizinin uzunluğu 32 bit işaretsiz tamsayıya sığar.) (Bir yorumda işaret ettiği için RobG'a giden sahne blog yayınımda Önceki testimin tam olarak doğru olmadığını.)

Bu, çoğu dizide döngü yineleme başına eklenmiş küçük bir miktardır, ancak seyrek dizisi, döngü için daha verimli bir yol olabilir, çünkü yalnızca var olan girdiler için döngü yapar. Örn, yukarıdaki dizi için, toplam üç kez döngü yaparız (anahtarlar için) "0", "10", ve "10000"- hatırlayın, onlar dizeler), 10,001 kere değil.

Şimdi, her seferinde bunu yazmak istemeyeceksiniz, bu yüzden bunu araç takımınıza koyabilirsiniz:

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

Ve sonra bunu şöyle kullanırdık:

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

Ya da sadece "çoğu vaka için yeterince iyi" testiyle ilgileniyorsanız, bunu kullanabilirsiniz, ancak yakın olmasına rağmen, tam olarak doğru değil:

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

4. Kullanın for-of (örtülü bir yineleyici kullanın) (ES2015 +)

ES2015 ekler yineleyiciler JavaScript’e Yineleyicileri kullanmanın en kolay yolu yeni for-of Beyan. Şuna benziyor:

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

Çıktı:

bir
b
c

Kapakların altında, yineleyici diziden ve onun içinden döngüleri, ondan değerleri almak. Bu kullanma sorunu yok for-in , nesnenin (dizi) tanımladığı bir yineleyici kullandığı için kullanır ve diziler yineleyicilerinin bunların üzerinden yinelemelerini tanımlar. girdileri (özellikleri değil). aksine for-in ES5'te, girişlerin ziyaret edildiği sıra, indekslerinin sayısal sırasıdır.

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

Bazen bir yineleyici kullanmak isteyebilirsiniz açıkça. Sen de yapabilirsin, ama daha çok for-of. Şuna benziyor:

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

Yineleyici, belirtimdeki Yineleyici tanımına uyan bir nesnedir. Onun next yöntem yeni bir değer döndürür sonuç nesnesi her aradığınızda Sonuç nesnesinin bir özelliği vardır. done, bittiğini ve bir mülk olup olmadığını bize söyler value Bu yinelemenin değeriyle. (done eğer istenirse false, value eğer istenirse undefined.)

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

  • values(): Yukarıda kullandığım bu. Her birinde bir yineleyici döndürür value bu yineleme için dizi girişi ("a", "b", ve "c" önceki örnekte).
  • keys(): Her birinde bir yineleyici döndürür value Bu yineleme için anahtardır (bizim için a yukarıda, bu olurdu "0", sonra "1", sonra "2").
  • entries(): Her birinde bir yineleyici döndürür value formdaki bir dizidir [key, value] bu iterasyon için.

Dizi gibi nesneler için

Gerçek diziler dışında, ayrıca dizi benzeri sahip olan nesneler length sayısal isimlerle özellik ve özellikler: NodeList örnekler arguments nesne vb. İçeriği nasıl geçeceğiz?

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

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

  1. kullanım forEach ve ilgili (ES5 +)

    Çeşitli fonksiyonlar Array.prototype "kasıtlı olarak jenerik" dir ve genellikle dizi benzeri nesneler üzerinden kullanılabilir. Function#call veya Function#apply. (Bkz. Barındırılan nesneler için Caveat Bu cevabın sonunda, ama bu nadir bir sorundur.)

    Kullanmak istediğini varsayalım forEach üzerinde Node'ler childNodes özelliği. Bunu yaparsı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ı yeniden kullanım için bir değişkene almak isteyebilirsiniz, örn .:

    // (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 kullan for döngü

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

  3. kullanım for-in  doğru şekilde

    for-in bir dizi ile aynı korumalarla birlikte dizi benzeri nesnelerle de çalışmalıdır; Yukarıda # 1 üzerinde ana bilgisayar tarafından sağlanan nesneler için uyarı geçerli olabilir.

  4. kullanım for-of (örtülü bir yineleyici kullanın) (ES2015 +)

    for-of Nesne tarafından sağlanan yineleyiciyi kullanır (varsa); Bunun, özellikle dizi tarafından sağlananlar gibi çeşitli dizi benzeri nesnelerle nasıl oynandığını görmemiz gerekecek. Örneğin, için şartname NodeList itibaren querySelectorAll yinelemeyi desteklemek için güncellendi. İçin spec HTMLCollection itibaren getElementsByTagName değildi.

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

    # 4'e bakın, yineleyicilerin nasıl oynadığını görmeliyiz.

Gerçek bir dizi oluştur

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. Kullan slice diziler yöntemi

    Kullanabiliriz slice Yukarıda belirtilen diğer yöntemler gibi diziler yöntemi "kasıtlı olarak jenerik" ve bu gibi dizi benzeri nesnelerle kullanılabilir:

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

    Örneğin, eğer bir NodeList doğru bir diziye, bunu yapabiliriz:

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

    Bakın Barındırılan nesneler için Caveat altında. Özellikle, bunun IE8 ve daha önceki sürümlerde başarısız olacağına dikkat edin; this bunun gibi.

  2. kullanım yaygın sözdizimi...)

    ES2015’leri kullanmak da mümkündür sözdizimi yay Bu özelliği destekleyen JavaScript motorları ile:

    var trueArray = [...iterableObject];
    

    Örneğin, eğer bir NodeList yayılan sözdizimi ile gerçek bir dizi içine bu oldukça özlü olur:

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

    Array.from (ES2015 +, ancak kolayca çok doldurulan), isteğe bağlı olarak girdileri bir eşleme işlevi aracılığıyla geçirerek, diziye benzer bir nesneden bir dizi oluşturur. Yani:

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

    Veya belirli bir sınıfa sahip öğelerin etiket adlarının bir dizisini 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;
    });
    

Barındırılan nesneler için Caveat

Eğer kullanırsan Array.prototype ile çalışır -Barındırmak sağlanan dizi benzeri nesneler (DOM listeleri ve JavaScript motoru yerine tarayıcı tarafından sağlanan diğer şeyler), ana bilgisayar tarafından sağlanan nesnenin düzgün şekilde davrandığından emin olmak için hedef ortamlarınızda test ettiğinizden emin olmanız gerekir. Çoğu uygun şekilde davranır (şimdi), ama test etmek önemlidir. Sebebi çoğu Array.prototype Kullanmak isteyeceğiniz yöntemlerin, özet olarak dürüst bir cevap veren, ana bilgisayar tarafından sağlanan nesneye dayanması [[HasProperty]] operasyon. Bu yazıdan yola çıkarak, tarayıcılar bunun için çok iyi bir iş çıkarmaktadır, ancak 5.1 spesifikasyon, ev sahibi tarafından sağlanan bir nesnenin dürüst olmamasına olanak tanımıştır. İçinde §8.6.2, bu bölümün başlangıcına yakın büyük masanın altındaki birkaç paragraf), diyor ki:

Ev sahibi nesneler, aksi belirtilmedikçe bu iç yöntemleri herhangi bir şekilde uygulayabilir; örneğin, bir ihtimal [[Get]] ve [[Put]] Belirli bir ana makine nesnesi için gerçekten özellik değerlerini getirin ve saklayın [[HasProperty]] her zaman üretir yanlış.

(ES2015'deki eşdeğer verbezi bulamadım, ancak hala böyle olması gerekiyor.) Bu yazıdan sonra, modern tarayıcılarda ortak olarak sunulan dizi benzeri nesneler [NodeList örneğin,] yap sap [[HasProperty]] Doğru, ama test etmek önemlidir.)


5980
2018-02-17 13:53



Bunu eklemek isterim .forEach verimli bir şekilde kırılamaz. Ara vermek için bir istisna atmanız gerekiyor. - Pijusn
@Pius: Döngüyü kırmak isterseniz kullanabilirsiniz. some. (Kırmaya izin vermeyi tercih ederdim forEach Ayrıca, onlar bana sormadılar. ;-)) - T.J. Crowder
@ T.J.Crowder True, asıl amacı olmadığı için daha çok bir iş gibi görünmesine rağmen. - Pijusn
@ user889030: Bir ihtiyacınız var , sonra k=0değil ;. Unutmayın, programlama birçok şeydir, bunlardan biri detaylara çok yakındır ... :-) - T.J. Crowder
@JimB: Yukarıda (ve length bir yöntem değildir). :-) - T.J. Crowder


Düzenle: Bu cevap umutsuzca güncel değil. Daha modern bir yaklaşım için, bakın bir dizide mevcut yöntemler. İlgi yöntemleri olabilir:

  • her biri için
  • harita
  • filtre
  • zip
  • azaltmak
  • her
  • bazı

Bir diziyi tekrarlamak için standart yol JavaScript vanilyalı mı for-loop:

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

Bununla birlikte, bu yaklaşımın yalnızca yoğun bir diziniz varsa ve her dizinin bir öğe tarafından işgal edilmesi durumunda iyi olduğunu unutmayın. Eğer dizi seyrek ise, o zaman bu yaklaşımla performans problemleri yaşayabilirsiniz, çünkü çok fazla indeks vermeyeceksiniz. Gerçekten mi dizide var. Bu durumda for .. in-loop daha iyi bir fikir olabilir. ancak, dizinin yalnızca istenen özelliklerinin (yani, dizi elemanlarının) etkin olduğundan emin olmak için uygun önlemleri kullanmanız gerekir. for..in-loop ayrıca eski tarayıcılarda veya ek özellikler olarak tanımlanacaktır. enumerable.

İçinde ECMAScript 5 dizi prototipinde bir forEach yöntemi olacak, ancak eski tarayıcılarda desteklenmiyor. Bu yüzden tutarlı bir şekilde kullanabilmek için onu destekleyen bir ortamınız olmalıdır (örneğin, node.js sunucu tarafı için JavaScript) veya bir "Polyfill" kullanın. Bununla birlikte, bu işlevselliğin Polyfill'i önemsizdir ve kodun okunmasını daha kolay hale getirdiğinden, dahil edilmesi iyi bir polyfilldir.


451
2018-02-17 13:55



neden ki for(instance in objArray)  doğru kullanım değil mi? bana göre daha basit görünüyor, ancak kullanım için doğru bir yoldan söz etmediğini duyuyor musunuz? - Dante1986
Satır içi uzunluğu önbellekleme kullanabilirsiniz: (var i = 0, l = arr.length; i <l; i ++) - Robert
İlk satırın sonunda virgül kasıtlı mı, yoksa bir yazım hatası mı (noktalı virgül olabilir)? - 9KSoft
@ wardha-Web Bu kasıtlıdır. Tek değişkenli birden fazla değişken bildirmemizi sağlar. var-kelime. Eğer bir noktalı virgül kullansaydık o zaman element küresel kapsamda ilan edilmiş olurdu (ya da JSHint, üretime ulaşmadan önce bize çığlık atacaktı). - PatrikAkerstrand


Kullanıyorsanız jQuery kütüphane kullanabilirsiniz jQuery.each:

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

DÜZENLE : 

Soruya göre, kullanıcı jquascript yerine jquascript kodu istiyor.

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

205
2018-02-17 14:01



Muhtemelen bu cevabı en çok kullanacağım. Bu sorunun en iyi cevabı değildir, ancak pratikte jQuery'yi kullanan kişiler için en basit ve en uygulanabilir olanı olacaktır. Sanırım hepimiz vanilya yolunu öğrenmeliyiz. Anlayışınızı genişletmek asla acıtmaz. - mopsyd
Sadece iyiliği için: jQuery her biri çok daha yavaş, ardından yerel çözümler. JQuery tarafından, mümkün olduğunda jQuery yerine native JavaScript kullanması önerilir. jsperf.com/browser-diet-jquery-each-vs-for-loop - Kevin Boss
Vanilya js kullanırken jQuery kullanmayın - Noe
Standart JS'ye bağlı kalmayın, yerel dil çözümü bulunmadığı sürece 3. taraf kütüphanelerini cevaptan uzak tutun - Steve K
Bana şunu hatırlatıyor: i.stack.imgur.com/ssRUr.gif - Ajedi32


Geriye doğru döngü

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

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

Avantajları:

  • Geçici olarak ilan etmene gerek yok len değişken veya karşılaştırmak array.length Her iterasyonda, bunların her ikisi de bir dakikalık optimizasyon olabilir.
  • Kardeşleri çıkarma DOM'dan ters sırada genellikle daha verimli. (Tarayıcının iç dizilerinde öğelerin daha az yer değiştirmesi gerekir.)
  • Eğer sen diziyi değiştirmek döngüde, endekste veya sonra ben (örneğin, bir öğeyi array[i]), daha sonra bir ileri döngü, sola kaydırılan öğeyi atlayacaktı benveya yeniden işleyin bensağa kaydırılan madde. Geleneksel bir döngüde, siz could güncelleştirme ben İşleme ihtiyacı olan bir sonraki maddeye işaret etmek - 1, ancak yinelemenin yönünü tersine çevirmek genellikle bir daha basit ve daha zarif çözüm.
  • Benzer şekilde, değiştirirken veya kaldırırken İç içe DOM elemanları, tersine işlenebilir hataları atlatmak. Örneğin, çocuklarını işlemeden önce ana düğümün içHTML'sini değiştirmeyi düşünebilirsiniz. Çocuk düğümüne ulaşıldığı zaman, ebeveynin dahiliHTML'si yazıldığı zaman yeni oluşturulmuş bir çocuk tarafından değiştirilen DOM'dan ayrılacaktır.
  • Bu daha kısa yazmak ve okumakMevcut diğer seçeneklerden daha. Her ne kadar kaybetse de forEach() ve ES6’lara for ... of.

Dezavantajları:

  • Eşyaları ters sırada işler. Sonuçlardan yeni bir dizi oluşturuyorsanız veya ekranda bir şeyler yazdırıyorsanız, doğal olarak çıktı tersine çevrilecek orijinal siparişe göre.
  • Siparişlerini korumak için kardeşleri DOM'a ilk çocuk olarak tekrar tekrar yerleştirmek daha az verimli. (Tarayıcı şeyleri doğru bir şekilde değiştirmeyi sürdürecektir.) DOM düğümlerini verimli ve sıralı bir şekilde oluşturmak için, sadece ileriye doğru ilerleyin ve normal olarak ekleyin (ve ayrıca bir "belge parçası" kullanın).
  • Ters döngü kafa karıştırıcı Genç geliştiricilere (Görünümünüze bağlı olarak bir avantaj olarak düşünebilirsiniz.)

Her zaman kullanmalı mıyım?

Bazı geliştiriciler, döngü için tersi kullanır varsayılan olarakileriye doğru döngü yapmak için iyi bir sebep yoksa.

Performans kazanımları genellikle önemsiz olsa da, çığlıklar şöyle:

"Sadece bunu listedeki her maddeye yap, siparişi umursamıyorum!"

Ancak pratikte bu değil Aslında niyetin güvenilir bir göstergesidir, çünkü bu durumlarda sizden ayırt edilemez. yap sipariş hakkında ve gerçekten gerek tersine döngü yapmak. Yani, aslında, "umurumda değil" niyetini doğru bir şekilde ifade etmek için başka bir yapıya ihtiyaç duyulacak, ECMAScript dahil olmak üzere şu anda pek çok dilde kullanılamayacak olan, ancak forEachUnordered().

Sipariş önemli değilse, ve verim (oyunun veya animasyon motorunun en içteki döngüsünde) bir endişe kaynağıdır, o zaman go-to deseniniz için tersine çevrimi kullanmak kabul edilebilir. Sadece mevcut kodda bir geri dönüş döngüsü görmeyi unutmayın mutlaka demek Siparişin alakasız olduğunu!

ForEach () kullanmak daha iyidir

Genel olarak daha yüksek düzeydeki kodlar için netlik ve güvenlik daha fazla endişe duyuyorsanız Array::forEach varsayılan düzeniniz olarak:

  • Okumak açıktır.
  • O gösterir ki ben blok içinde kaydırılmayacak (her zaman uzun süre saklanabilecek olası bir sürpriz) for ve while döngüsü.)
  • Kapaklar için ücretsiz bir kapsam sağlar.
  • Yerel değişkenlerin sızmasını ve dış değişkenlerin (ve mutasyonunun) kazara çarpmasını azaltır.

Ardından kodunuzda tersine dönme döngüsünü gördüğünüzde, bunun iyi bir nedenden ötürü tersine çevrilmiş olduğuna dair bir ipucu (belki de yukarıda açıklanan nedenlerden biri). Ve döngü için geleneksel bir ileriyi görmek, değişimin gerçekleşebileceğini gösterebilir.

(Eğer niyet tartışması size bir anlam ifade etmiyorsa, siz ve kodunuz Crockford'un konuşmasını izlemekten yararlanabilir. Programlama Stili ve Beyniniz.)


O nasıl çalışır?

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

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

Fark edeceksiniz i-- orta cümledir (genellikle bir karşılaştırma görürsünüz) ve son madde boştur (genellikle gördüğümüz yer) i++). Bu şu demek oluyor i-- aynı zamanda şart devamı için. Önemli olarak, yürütülür ve kontrol edilir önce her yineleme.

  • Nasıl başlayabilir? array.length patlamaksızın mı?

    Çünkü i-- koşar önce her yinelemede, ilk iterasyonda, öğeye array.length - 1 ile herhangi bir sorundan kaçınan Dizi-out-of-aut  undefined öğeler.

  • Neden index 0'dan önce yinelemeyi kesmiyor?

    Döngü, koşul ne zaman yinelemeyi durduracak i-- Falsey değerini değerlendirir (0 olduğunda).

    Hile o farklıdır --i, takip i-- operatör azaltma i ama değeri verir önce azaltma. Konsolunuz bunu gösterebilir:

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

    [5, 5, 4]

    Yani son iterasyonda, ben daha önce 1 ve i-- ifade onu değiştirir 0 ama aslında verim 1 (doğruluk), ve böylece durum geçer. Sonraki iterasyonda i-- değişiklikler ben için -1 ama verim 0 (falsey), infazın dibinin hemen dışına çıkmasına sebep olur.

    Döngü için geleneksel ilerlemelerde i++ ve ++i değiştirilebilir (Douglas Crockford'un işaret ettiği gibi). Ancak geri dönüş için, bizim azalmamız da bizim durumumuzun ifadesi olduğu için, i-- Öğeyi dizin 0'da işlemek istiyorsak.


önemsiz şeyler

Bazı insanlar tersine küçük bir ok çizmeyi sever for döngü ve bir göz kırparak bitirin:

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

Krediler bana, ters döngü için yararlarını ve dehşetlerini gösterdiği için WYL'ye gider.


88
2018-05-02 14:21



Eklemek unuttum kriterler. Ayrıca, geri dönüşün 6502 gibi 8 bitlik işlemcilerde önemli bir optimizasyon olduğunu söylemeyi de unutmuştum; - joeytwiddle
Ters döngü için buna ne dersin? var i = dizi.length; (i--) {... - Kabb5
Üzgünüm @ Kabb5 AFK'ydim. Evet bu döngü oldukça açık ve aslında aynı. - joeytwiddle
Ah, eski güzel "Ok ve bir Wink" kod deseni. Onu seviyorum! +1 benden! - Matheus Avellar
Aynı cevap çok daha açık bir şekilde verilir İşte (farklı bir soru üzerine). - joeytwiddle


Bazı Cstil dilleri kullanımı foreach sayılar yoluyla döngü yapmak. JavaScript’te bu işlem for..in döngü yapısı:

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

Bir yakalama var. for..in Nesnenin sayısız üyelerinden ve prototipindeki üyelerin her birine girer. Nesnenin prototipiyle miras alınan değerlerin okunmasını önlemek için, özelliğin nesneye ait olup olmadığını kontrol edin:

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

Bunlara ek olarak, ECMAScript 5 ekledi bir forEach yöntem Array.prototypeBir dizinin bir calback'i kullanarak numaralandırılması için kullanılabilir (polyfill dokümanlar içinde olduğundan eski tarayıcılar için kullanabilirsiniz):

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

Bunu not etmek önemlidir Array.prototype.forEach geri dönüş döndüğünde kırılmaz false. jQuery ve Underscore.js kendi varyasyonlarını sağlamak each kısa devre yapabilen döngüler sağlamak.


71
2018-02-17 14:00



Öyleyse, C biçimindeki dillerdeki gibi bir döngü veya bir foreach döngüsü için yaptığımız gibi bir ECMAScript5 foreach döngüsünden nasıl ayrılıyoruz? - Ciaran Gallagher
@CiaranG, JavaScript’te görülmesi sık görülen bir şey each izin veren yöntemler return false döngüden kurtulmak için kullanılır, ancak forEach Bu bir seçenek değil. Harici bir bayrak kullanılabilir (örn. if (flag) return;Ancak, sadece işlev gövdesinin geri kalanının çalışmasını engeller, forEach koleksiyonun tamamında yinelenmeye devam ediyor. - zzzzBov


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

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

Önbelleğe alma ile bazı performans optimizasyonları alabilirsiniz. myArray.length ya da geriye doğru iterasyon.


30
2018-02-17 13:55



için (var i = 0, uzunluk = myArray.length; i <length; i ++) yapmalı - Edson Medina
@EdsonMedina Bu da denilen yeni bir global değişken oluşturacak length. ;) - joeytwiddle
@joeytwiddle Evet, ancak bu yazının kapsamı dışında. Yine de global bir değişken oluşturacaksın. - Edson Medina
@EdsonMedina Özür dilerim, tamamen yanlış anladım. kullanma ,bir ödevden sonra değil yeni bir global tanıtın, bu yüzden öneriniz sadece ince! Bunu farklı bir problem için karıştırıyordum: = bir ödevden sonra yaratıyor yeni bir küresel. - joeytwiddle
Dikkatli olun ben değil ilmek için yerel. JavaScript'in blok kapsamı yok. Bildirmek muhtemelen daha iyi var i, length, arrayItem; Bu yanlış anlamadan kaçınmak için döngüden önce. - James


bir her biri için uygulama (jsFiddle'ta görmek):

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

25
2018-04-10 00:26



Bu yineleyici, gereksiz uzunluk hesaplama yapıyor. İdeal bir durumda, liste uzunluğu sadece bir kez hesaplanmalıdır. - MIdhun Krishna
@MIdhunKrishna Cevabımı ve jsFiddle'ı güncelledim ama düşündüğünüz kadar basit olmadığını unutmayın. Şuna göz at soru - nmoliveira
Tam ve doğru uygulama burada bulunabilir: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/... - marciowb


Diziyi boşaltma sakıncası yoksa:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

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


25
2018-03-10 02:37



Eğer seyrek bir dizi gibi olursan işe yaramıyor [1, 2, undefined, 3]. - M. Grzywaczewski
... ya da gerçekten her şey dürüst: [1, 2, 0, 3] veya [true, true, false, true] - joeytwiddle


Bunun eski bir yazı olduğunu biliyorum ve çok fazla büyük cevap var. Biraz daha fazla bütünlük için başka birini kullanarak atacağımı düşündüm. angularjs. Tabii ki, bu sadece Angular kullanıyorsanız geçerlidir, tabii ki yine de onu koymak isterim.

angular.forEach 2 argüman ve isteğe bağlı üçüncü argüman alır. Birinci argüman, yineleme yapılacak nesne (dizi), ikinci argüman yineleyici işlevidir ve isteğe bağlı üçüncü argüman nesne bağlamıdır (temel olarak 'bu' olarak döngü içinde belirtilir.

ForEach döngü açı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 kopyalamanın başka bir yolu 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);

Yine de, 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 artıları ve eksilerini kullanma angular.forEach vanilya aromalı olarak inşa edilenin aksine işlev for döngü.

Artıları

  • Kolay okunabilirlik
  • Kolay yazılabilirlik
  • Mümkün ise, angular.forEach ES5 forEach döngüsünü kullanacaktır. Şimdi, her döngüde olduğu gibi eksiler bölümünde verimlilik elde edeceğim çok döngüler için daha yavaş. Bunu bir profesyonel olarak belirtiyorum çünkü tutarlı ve standart olmak güzel.

Tam olarak aynı şeyi yapan aşağıdaki 2 iç içe döngüleri düşünün. Diyelim ki, 2 tane nesne dizimiz var ve her bir nesne bir dizi sonuç içeriyor, herbiri bir değer dizisi olan bir dizi özelliğe sahip (veya her neyse). Ve diyelim ki, her bir sonuç üzerinde yinelemeliyiz ve eğer eşitse, o zaman bir eylem gerçekleştirmeliyiz:

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 üçlü gömülü yazdım ve çok okumak zor ve bu konu için yaz.

Eksileri

  • Verimlilik. angular.forEachve yerel forEachbu konuda hem çok fazla normalden daha yavaş for döngü .... yaklaşık % 90 daha yavaş. Dolayısıyla, büyük veri kümeleri için for döngü.
  • Ara vermeyin, devam edin veya destek verin. continue aslında "tarafından desteklenmektedir"kaza", devam etmek angular.forEach basit bir return; işlevindeki gibi ifade angular.forEach(array, function(item) { if (someConditionIsTrue) return; }); Bu iterasyon için fonksiyondan devam etmesine neden olur. Bu, aynı zamanda yerel olmasından kaynaklanmaktadır forEach kırmayı desteklemiyor ya da devam ediyor.

Eminim diğer çeşitli artıları ve eksileri de vardır ve lütfen uygun gördüğünüz herhangi bir şey eklemekten çekinmeyin. Bunu hissediyorum, alt satır, verimliliğe ihtiyacınız varsa, sadece yerli ile sopa for Döngü ihtiyaçlarınız için döngü. Ancak, veri kümeleriniz küçükse ve okunabilirlik ve yazılabilirlikten vazgeçmek için bir miktar verim yeterli ise, o zaman angular.forEach O kötü çocukta.


25
2018-06-20 22:56





Şimdi kolay bir çözüm kullanmak underscore.js kitaplığı. Gibi birçok yararlı araç sağlıyor each ve işi otomatik olarak yerel olarak delege edecek forEach mümkün ise.

Bir CodePen örneği nasıl çalışır:

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

Ayrıca bakınız


24
2017-07-17 09:07





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

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

Yöntemden arayacak array[0] için array[2]. Birincisi, bu, sahip olmadığınız değişkenleri ilk önce, ikinci sırada dizideki değişkenlere sahip olmayacak ve üçüncü bu da kodu daha iyi hale getirecektir. Bak, benim 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 eğer bunun bir işlev olmasını istiyorsanız, bunu yapabilirsiniz:

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

Eğer kırılmak isterseniz, biraz daha mantık:

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

Örnek:

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

Döndürür:

//Hello
//World
//!!!

21
2017-11-02 02:23