JavaScript'te bir dizi üzerinde for-each?

JavaScript kullanarak bir dizideki tüm girdiler arasında nasıl döngü yapabilirim?

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

forEach(instance in theArray)

Burada theArray benim dizimdir, ancak bu yanlış gibi görünüyor.

Çözüm

TL;DR

  • Güvenli bir şekilde kullanmadığınız veya en azından neden sizi ısırabileceğinin farkında olmadığınız sürece `for-in' kullanmayın.
  • En iyi bahisleriniz genellikle
  • bir for-of döngüsü (yalnızca ES2015+),
  • Array#forEach ([spec][1] | [MDN][2]) (veya some ve benzeri akrabaları) (sadece ES5+),
  • basit bir eski moda for döngüsü,
  • ya da koruma önlemleriyle birlikte "içeride". Ancak keşfedilecek daha çok şey var, okumaya devam edin...

    JavaScript, diziler ve dizi benzeri nesneler arasında döngü oluşturmak için güçlü anlambilimlere sahiptir. Cevabı iki bölüme ayırdım: Gerçek diziler için seçenekler ve arguments nesnesi, diğer yinelenebilir nesneler (ES2015+), DOM koleksiyonları vb. gibi sadece dizi benzeri şeyler için seçenekler. ES2015 seçeneklerini şimdi ES5 motorlarında bile ES2015'ten ES5'e transpiling yaparak kullanabileceğinizi hemen belirteyim. Daha fazlası için "ES2015 transpiling" / "ES6 transpiling" araması yapın... Tamam, seçeneklerimize bakalım:

    Gerçek Diziler İçin

    Şu anda en geniş şekilde desteklenen sürüm olan [ECMAScript 5][3] ("ES5")'te üç seçeneğiniz vardır ve [ECMAScript 2015][4] ("ES2015", "ES6")'te iki tane daha eklenmiştir:

  1. forEach` ve ilgili öğeleri kullanın (ES5+)
  2. Basit bir for döngüsü kullanın
  3. for-in'i doğru kullanın
  4. for-of` kullanın (örtük olarak bir yineleyici kullanın) (ES2015+)
  5. Açıkça bir yineleyici kullanın (ES2015+) Detaylar:

    1. forEach` ve ilgili kullanın

    ES5 tarafından eklenen Array özelliklerine erişiminizin olduğu (doğrudan veya polyfills kullanarak) herhangi bir belirsiz modern ortamda (yani IE8 değil), forEach ([spec][1] | [MDN][2]) kullanabilirsiniz:

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

forEachbir geri çağırma fonksiyonu ve isteğe bağlı olarak bu geri çağırmayı çağırırkenthisolarak kullanılacak bir değer kabul eder (yukarıda kullanılmamıştır). Geriçağırım, seyrek dizilerde var olmayan girdileri atlayarak, dizideki her girdi için sırayla çağrılır. Yukarıda sadece bir argüman kullanmış olmama rağmen, geri çağrı üç argümanla çağrılır: Her bir girdinin değeri, o girdinin indeksi ve üzerinde yineleme yaptığınız diziye bir referans (fonksiyonunuzda zaten yoksa). IE8 gibi eski tarayıcıları desteklemediğiniz sürece (NetApps bu yazının yazıldığı Eylül 2016 itibariyle pazar payının %4'ün biraz üzerinde olduğunu gösteriyor),forEach'i genel amaçlı bir web sayfasında şim olmadan rahatlıkla kullanabilirsiniz. Eski tarayıcıları desteklemeniz gerekiyorsa, forEach için shimming/polyfilling kolayca yapılabilir (çeşitli seçenekler için "es5 shim" araması yapın). forEach, yineleme işlevine argüman olarak sağlandıkları ve sadece o yineleme için güzel bir şekilde kapsamlandırıldıkları için, dizinleme ve değer değişkenlerini içeren kapsamda bildirmek zorunda kalmamanız gibi bir avantaja sahiptir. Her dizi girişi için bir fonksiyon çağrısı yapmanın çalışma zamanı maliyeti konusunda endişeleniyorsanız, endişelenmeyin; [details](http://blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html). Ek olarak,forEach' "hepsinde döngü" işlevidir, ancak ES5, aşağıdakiler de dahil olmak üzere diğer birçok yararlı "dizi boyunca yolunuzu çalışın ve bir şeyler yapın" işlevini tanımlamıştır:

  • [every][5] (geri çağırma false ya da başka bir şey döndürdüğünde döngüyü durdurur)
  • [some][6] (geri arama ilk kez true veya doğru bir şey döndürdüğünde döngüyü durdurur)
  • [filter][7] (filtre işlevinin true döndürdüğü öğeleri içeren ve false döndürdüklerini çıkaran yeni bir dizi oluşturur)
  • [map][8] (geri arama tarafından döndürülen değerlerden yeni bir dizi oluşturur)
  • [reduce][9] (önceki değerleri aktararak geri çağrıyı tekrar tekrar çağırarak 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][10] (reduce gibi, ancak artan yerine azalan sırada çalışır)

    2. Basit bir for döngüsü kullanın

    Bazen eski yöntemler 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şmeyecekse ve performansa duyarlı bir koddaysa (pek olası değil), uzunluğu önceden yakalayan biraz daha karmaşık bir sürüm tiny 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 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ıyla, son bir parça güç elde etmeniz nadiren gerekir. ES2015 ve daha yüksek sürümlerde, indeks ve değer değişkenlerinizi for döngüsü 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"
let a = ["a", "b", "c"];
for (let index = 0; index < a.length; ++index) {
    let value = a[index];
    console.log(index, value);
}
try {
    console.log(index);
} catch (e) {
    console.error(e);   // "ReferenceError: index is not defined"
}
try {
    console.log(value);
} catch (e) {
    console.error(e);   // "ReferenceError: value is not defined"
}

Bunu yaptığınızda, her döngü yinelemesi için yalnızca value değil, index de yeniden oluşturulur, yani döngü gövdesinde oluşturulan kapanışlar, o belirli yineleme için oluşturulan indexe (ve valueya) bir 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);
    });
}
let divs = document.querySelectorAll("div");
for (let index = 0; index < divs.length; ++index) {
    divs[index].addEventListener('click', e => {
        console.log("Index is: " + index);
    });
}
<div>zero</div>
<div>one</div>
<div>two</div>
<div>three</div>
<div>four</div>

Eğer beş div'iniz olsaydı, "Index is: 0" ve eğer ilkine tıklarsanız "Index is: 4" eğer sonuncuya tıklarsanız. Eğer let' yerinevar' kullanırsanız bu çalışmaz.

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

İnsanlar size for-in' kullanmanızı söyleyecektir, ancakfor-in' bunun için değildir][11]. for-inbir nesnenin *sayılabilir özellikleri* üzerinde döngü yapar, bir dizinin indeksleri üzerinde değil. ES2015'te (ES6) bile **sıra garanti edilmez**. ES2015+ nesne özellikleri için bir sıra tanımlar ([[[OwnPropertyKeys]]](https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys), [[[Enumerate]]](https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots-enumerate) ve [Object.getOwnPropertyKeys][12] gibi bunları kullanan şeyler aracılığıyla), ancakfor-inin bu sırayı izleyeceğini **tanımlamaz**. (Ayrıntılar [bu diğer yanıtta][13].) Bir dizi üzerindefor-in` için tek gerçek kullanım durumları şunlardır:

  • İçinde büyük boşluklar olan bir [seyrek diziler][14] veya
  • Eleman olmayan özellikler kullanıyorsunuz ve bunları döngüye dahil etmek istiyorsunuz Sadece bu ilk örneğe bakarak: Eğer uygun önlemleri alırsanız, bu sparese dizi elemanlarını ziyaret etmek için for-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 
Yorumlar (24)

Not: Bu cevap umutsuzca güncelliğini yitirmiştir. Daha modern bir yaklaşım için bir dizi üzerinde kullanılabilen yöntemler'e bakın. İlgi çekici yöntemler şunlar olabilir:

  • forEach
  • Harita
  • Filtre
  • zip
  • azaltın
  • her
  • bazı

JavaScript]2'de bir diziyi yinelemenin standart yolu vanilla for döngüsü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 ve her dizin bir eleman tarafından işgal ediliyorsa iyi olduğunu unutmayın. Dizi seyrekse, dizide gerçekte var olmayan birçok indis üzerinde yineleme yapacağınızdan, bu yaklaşımla performans sorunlarıyla karşılaşabilirsiniz. Bu durumda, bir for .. in döngüsü daha iyi bir fikir olabilir. Bununla birlikte, for..in döngüsü eski tarayıcılarda da numaralandırılacağından veya ek özellikler enumerable olarak tanımlanmışsa, dizinin yalnızca istenen özelliklerinin (yani dizi öğelerinin) üzerinde işlem yapılmasını sağlamak için uygun önlemleri almalısınız.

ECMAScript 5]3'te dizi prototipi üzerinde bir forEach yöntemi olacaktır, ancak eski tarayıcılarda desteklenmemektedir. Dolayısıyla, bunu tutarlı bir şekilde kullanabilmek için ya bunu destekleyen bir ortama sahip olmanız (örneğin, sunucu tarafı JavaScript için Node.js) ya da bir "Polyfill" kullanmanız gerekir. Bununla birlikte, bu işlevsellik için Polyfill önemsizdir ve kodun okunmasını kolaylaştırdığından, dahil edilmesi iyi bir polyfill'dir.

Yorumlar (4)

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

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

myArray.length` dosyasını önbelleğe alarak veya geriye doğru yineleyerek bazı performans optimizasyonları elde edebilirsiniz.

Yorumlar (5)