JavaScript için sözdizimini kullanarak döngü sayacı / dizini al


318

Dikkat:

Soru hala for…ofdöngüler için geçerlidir .> for…inBir Dizi üzerinden yineleme yapmak için kullanmayın, bunu bir nesnenin özellikleri üzerinde yineleme yapmak için kullanın . Dedi ki, bu


for…inJavaScript temel sözdiziminin şöyle göründüğünü anlıyorum :

for (var obj in myArray) {
    // ...
}

Peki döngü sayacını / dizinini nasıl edinebilirim ?

Muhtemelen böyle bir şey yapabileceğimi biliyorum:

var i = 0;
for (var obj in myArray) {
    alert(i)
    i++
}

Ya da iyiler bile:

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

Ama daha basit bir for-indöngü kullanmayı tercih ederim . Bence daha iyi görünüyorlar ve daha anlamlılar.

Daha basit veya daha zarif bir yol var mı?


Python'da bu kolay:

for i, obj in enumerate(myArray):
    print i

6
Diziler için ... in için kullanmayın. Her neyse, özelliklerin değerlerini değil, özellik adlarını yineler.
Felix Kling

1
Bu bir dizi, bir nesne değil, değil mi? Yani alert(obj)?
Rocket Hazmat

Yanıtlar:


546

for…indeğer değil, özellik adları üzerinde yineleme yapar ve bunu belirtilmemiş bir sırayla yapar (evet, ES6'dan sonra bile). Dizileri yinelemek için kullanmamalısınız. Onlar için, forEachhem değeri hem de dizini verdiğiniz işleve ileten ES5'in yöntemi vardır:

var myArray = [123, 15, 187, 32];

myArray.forEach(function (value, i) {
    console.log('%d: %s', i, value);
});

// Outputs:
// 0: 123
// 1: 15
// 2: 187
// 3: 32

Ya Array.prototype.entriesda şu anda mevcut tarayıcı sürümlerinde destek olan ES6'lar :

for (const [i, value] of myArray.entries()) {
    console.log('%d: %s', i, value);
}

Genel olarak yinelenebilirler için (a for…ofyerine bir döngü kullanacağınız yerde for…in) yerleşik bir şey yoktur, ancak:

function* enumerate(iterable) {
    let i = 0;

    for (const x of iterable) {
        yield [i, x];
        i++;
    }
}

for (const [i, obj] of enumerate(myArray)) {
    console.log(i, obj);
}

gösteri

Aslında for…in- numaralandırma özellikleri - demek istediyseniz, ek bir sayaca ihtiyacınız olacaktır. Object.keys(obj).forEachişe yarayabilir, ancak yalnızca kendi özelliklerini içerir ; for…inprototip zincirinin herhangi bir yerinde numaralandırılabilir özellikler içerir.


2
Ah tamam. Kafam karışmıştı. JavaScript'in for-in'in Python'unkiyle aynı olduğunu düşündüm. Açıklama için teşekkürler.
hobbes3

1
@quantumpotato: lets varblok kapsamlıdır. consts değişmez.
Ry-

1
bu ayrıntılı bir cevaptı, bunun için teşekkürler. Tartışılan her şeyi gerçekten netleştirdi
Dheeraj Bhaskar

1
aptalca bir soru ama% d ve% s aslında ne anlama geliyor, yoksa olmasını istediğim herhangi bir harf olabilir mi?
klewis

2
@klewis: %dbir tamsayıyı ve %sbir dizeyi biçimlendirir. Printf tabanlıdır . Console.spec.whatwg.org/#formatter adresinde bir özellik devam ediyor .
Ry-

163

ES6'da, döngü için kullanmak iyidir. Bunun için dizin alabilirsiniz

for (let [index, val] of array.entries()) {
        // your code goes here    
}

For-döngüsünde çalışmasına izin veren bir yineleyiciArray.entries() döndürdüğünü unutmayın ; bunu bir dizi anahtar / değer çifti çifti döndüren Object.entries () ile karıştırmayın .


9
Bu, kabul edilenden çok daha iyi bir cevap!
trusktr

3
Bence bu çözüm her şeyden daha iyi ... Döngü sözdiziminin nomralini kullanıyor ve ayrı bir işlev kullanmak zorunda değilsiniz. Başka bir deyişle, sözdizimsel olarak daha iyi. OP bunu istemiş gibi görünüyor.
u8y7541

1
entries()boş bir nesne dönen bir: {}. Bunun neden olacağına dair bir fikrin var mı? Benim arraybir Nesneler Dizisidir.
Joshua Pinter

@JoshuaPinter deneyin Object.entries(array)yerinearray.entries()
tonyg

2
Bunu yapması gerekiyordu, Joshua - nesne bir yineleyici, next()her çağrıldığında dizideki sonraki girdileri döndürecek bir yönteme sahip bir nesne . İçinde (görünür) veri yok; next()perde arkasındaki for-of işlevini çağırarak verileri temel alınan nesnede alırsınız . cc @tonyg
Shog9

26

Buna ne dersin

let numbers = [1,2,3,4,5]
numbers.forEach((number, index) => console.log(`${index}:${number}`))

Burada array.forEach, bu yöntem, bir yer alır indexdizide o anda işlemlendirilmekte olan elemanın indisidir parametre.


1
burada en iyi cevap
codepleb

4
Seçilen cevap bundan 6 yıl önce gönderildi ve zaten aynı şey var ...
Deiv

Foreach, optimizasyon için iyi değildir, çünkü breakmevcut değildir.
smartworld-dm

20

Küçük dizi koleksiyonları için çözüm:

for (var obj in arr) {
    var i = Object.keys(arr).indexOf(obj);
}

arr - ARRAY, obj - Geçerli öğenin ANAHTARI, i - COUNTER / INDEX

Uyarı: Yöntem anahtarları () IE sürümü <9 için kullanılamaz, Polyfill kodunu kullanmalısınız . https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys


7
Ben önermek: bunun yerine bir sayaç kullanın, döngüde artırın.
mayankcpdixit

2
Mayankcpdixit'e eklenirken, bunun yerine bir sayaç kullanın, çünkü indexOf olumsuz bir performans etkisine sahip olabilir.
Dean Liu

1
Nesne ne kadar büyük olursa, o kadar yavaş olur. Bu ölçeklenmez.
dchacke

2
Bu amaçsızca yavaş tür ve çünkü karmaşık olduğunu var i = 0;ve i++;daha kısa ve daha verimlidir. Ayrıca, kendi mülkleri olmayan numaralandırılabilir mülkler için çalışmaz.
Ry-

1
@trusktr: Ve eğer gerekiyorsa… bunu hala kullanmamalısınız. Koleksiyonu değiştirdiğinizde sayacı değiştirmeniz yeterlidir. Yerinde olması gerekmiyorsa, bunun yerine hoş bir işlevsel dönüşüm yapın.
Ry-

13

Döngüler için bir Nesnenin özellikleri üzerinde yineleme yapar. Bazen çalışsalar bile bunları Diziler için kullanmayın.

Nesne özelliklerinin indeksi yoktur, hepsi eşittir ve belirli bir sırada çalıştırılması gerekmez. Mülkleri saymak istiyorsanız, ekstra sayacı ayarlamanız gerekir (ilk örneğinizde yaptığınız gibi).

bir Dizi üzerinde döngü:

var a = [];
for (var i=0; i<a.length; i++) {
    i // is the index
    a[i] // is the item
}

bir nesne üzerinde döngü:

var o = {};
for (var prop in o) {
    prop // is the property name
    o[prop] // is the property value - the item
}

3
Asla (var i=0; i<a.length; i++)boşa harcanan kaynakları yapmayın . Kullanın(var i=0, var len = a.length; i<len; i++)
Félix Sanz

16
@FelixSanz: Atık kaynakları mı? Olmaz. Bu, neredeyse hiç gerekli olmayan erken bir mikro optimizasyon ve var i=0; i<a.length; i++)yine de her iyi javascript motoru tarafından optimize edilen standart döngü deseni.
Bergi

3
@FelixSanz: Evet ve var i=0; i<a.length; i++en iyi uygulama.
Bergi

1
ÖPÜCÜK . Buna gerçekten ihtiyacınız olan döngüler yazarsanız, ya yanlış bir şey yapıyorsunuz ya da gerekliliği için "en iyi uygulama" dan daha iyi bir argümanınız vardır. Evet, standart bir uygulamadır, ancak genel performans optimizasyonu için değil, sadece mikro optimizasyon içindir.
Bergi

3
KISS her yerde geçerlidir. Erken optimizasyon bir anti-uygulamadır.
Bergi

7

Diğerleri söylediler, bir dizi üzerinde yineleme için for..in kullanmamalısınız.

for ( var i = 0, len = myArray.length; i < len; i++ ) { ... }

Daha temiz bir sözdizimi istiyorsanız, forEach kullanabilirsiniz:

myArray.forEach( function ( val, i ) { ... } );

Bu yöntemi kullanmak istiyorsanız, eski tarayıcılara destek eklemek için ES5 şemasını eklediğinizden emin olun.


2

Cevap rushUp tarafından verilen Doğru ama bu daha uygun olacak

for (let [index, val] of array.entries() || []) {
   // your code goes here    
}

1

İşte eachWithIndexyinelenebilir her şeyle çalışan bir işlev .

eachWithKeyNesneleri kullanarak çalışan benzer bir işlev de yazabilirsiniz for...in.

// example generator (returns an iterator that can only be iterated once)
function* eachFromTo(start, end) { for (let i = start; i <= end; i++) yield i }

// convers an iterable to an array (potential infinite loop)
function eachToArray(iterable) {
    const result = []
    for (const val of iterable) result.push(val)
    return result
}

// yields every value and index of an iterable (array, generator, ...)
function* eachWithIndex(iterable) {
    const shared = new Array(2)
    shared[1] = 0
    for (shared[0] of iterable) {
        yield shared
        shared[1]++
    }
}

console.log('iterate values and indexes from a generator')
for (const [val, i] of eachWithIndex(eachFromTo(10, 13))) console.log(val, i)

console.log('create an array')
const anArray = eachToArray(eachFromTo(10, 13))
console.log(anArray)

console.log('iterate values and indexes from an array')
for (const [val, i] of eachWithIndex(anArray)) console.log(val, i)

Jeneratörler için iyi olan şey, tembel olmaları ve başka bir jeneratörün sonucunu argüman olarak alabilmeleridir.


1

Bu, (yavaş) ana arama örneği ile bir dizin ve geçirilen herhangi bir jeneratör işlevinin değerini veren bir bileşik yineleyicinin sürümü:

const eachWithIndex = (iterable) => {
  return {
    *[Symbol.iterator]() {
      let i = 0
      for(let val of iteratable) {
        i++
          yield [i, val]
      }
    }
  }

}

const isPrime = (n) => {
  for (i = 2; i < Math.floor(Math.sqrt(n) + 1); i++) {
    if (n % i == 0) {
      return false
    }
  }
  return true
}

let primes = {
  *[Symbol.iterator]() {
    let candidate = 2
    while (true) {
      if (isPrime(candidate)) yield candidate
        candidate++
    }
  }
}

for (const [i, prime] of eachWithIndex(primes)) {
  console.log(i, prime)
  if (i === 100) break
}


Neden eachWithIndex[Symbol.iterator]sadece bir fonksiyon yerine bir fonksiyonunuz var eachWithIndex? eachWithIndexbütün mesele yinelenebilir arayüzü tatmin etmez Symbol.iterator.
Ry-

@ Ry- İyi yakalama, eachWithIndextekrarlanabilir kabul ve kapatılmış kompozit tekrarlanabilir geri dönmek için değiştirildi.
akurtser

1

Herkesin yayınladığı çok iyi cevapların üstüne, en performanslı çözümün ES6 olduğunu eklemek istiyorum entries. Buradaki birçok geliştirici için kontrendike görünüyor, bu yüzden bu mükemmel benchamrk'i yarattım .

resim açıklamasını buraya girin

~ 6 kat daha hızlı. Temel olarak aşağıdakilere ihtiyaç duymadığı için: a) diziye bir kereden fazla erişim ve b) dizini yayınlama.

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.