2012-04-16 2 views
99

Осторожно. Не используйте для ... in для итерации по массиву, используйте его для перебора объектов объекта.
Тем не менее, этот вопрос по-прежнему применяется для ... петель.Как получить счетчик циклов/индекс, используя синтаксис for ... в JavaScript?


Я понимаю, что основной для ... в синтаксисе JavaScript выглядит следующим образом:

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

Но как я могу получить счетчик цикла/индекс? Я знаю, что я мог бы сделать что-то вроде:

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

или даже хороший, старый:

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

Но я предпочел бы использовать более простой для в цикле. Я думаю, они выглядят лучше и имеют больше смысла.

Но есть ли более простой или элегантный способ?

В Python это легко:

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

Не используйте для ... в для массивов. И так или иначе, он выполняет итерации над именами свойств, а не значениями свойств. –

+1

Это массив, а не объект, не так ли? Итак, 'alert (obj)'? –

ответ

177

for…in перебирает имена свойств, а не ценности, и делает это in an unspecified order (да, даже после того, как ES6). Вы не должны использовать его для перебора массивов. Для них есть forEach метод ES5, что проходит как значение и индекс к функции вы даете ему:

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 

Или ES6-х Array.prototype.entries, который теперь поддерживает через текущие версии браузеров:

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

Для итерируемые в целом (где вы будете использовать for…of петли, а не for…in), нет ничего встроенного, однако:

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

demo

Если вы на самом деле имели в виду for…in - перечислимые объекты - вам понадобится дополнительный счетчик. Object.keys(obj).forEach может работать, но включает только собственный; for…in включает перечислимые свойства в любой точке цепи прототипа.

+0

О, хорошо. Я был смущен. Я думал, что JavaScript-in-in был таким же, как у Python's. Спасибо за разъяснения. – hobbes3

+0

Фактически, obj будет индексом массива, но нет никакой гарантии, что он в порядке и что он не будет содержать другие имена свойств. –

+0

Вам не нужно делать var i = 0, потому что let неизменны? – quantumpotato

9

For-in-loops перебирают свойства объекта. Не используйте их для массивов, даже если они иногда работают.

Свойства объекта тогда не имеют индекса, все они равны и не требуются для прохождения в определенном порядке. Если вы хотите подсчитать свойства, вам нужно будет настроить дополнительный счетчик (как в первом примере).

цикл по массиву:

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

петля над объектом:

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

Никогда не делайте' (var i = 0; i

+5

@FelixSanz: Ресурсы для отходов? Ни в коем случае это преждевременная микро-оптимизация, которая вряд ли когда-либо понадобится, и' var i = 0; i Bergi

+0

Лучшая практика - это лучшие практики! –

3

Как уже сказал, вы не должны использовать for..in перебрать массив.

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

Если вы хотите более чистый синтаксис, вы можете использовать Foreach:

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

Если вы хотите использовать этот метод, убедитесь, что вы включили ES5 подкладку, чтобы добавить поддержку для старых браузеров.

15

Решение для небольших коллекций массива:

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

обр - ARRAY, OBJ - КЛЮЧ текущего элемента, я - COUNTER/INDEX

Примечание: метод ключей() не доступен для версии IE < 9 , вы должны использовать код Polyfill. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

+0

Обратите внимание, что метод indexOf НЕ доступен для IE 8/11 – LPing

+5

Я бы предложил: вместо этого используйте счетчик, увеличьте его в цикле. – mayankcpdixit

+2

Добавляя к mayankcpdixit, используйте счетчик вместо этого, потому что indexOf может оказать отрицательное влияние на производительность. –

58

В ES6 он хорош для использования в петле. Вы можете получить индекс в течение от как этого

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

Обратите внимание, что Array.entries() возвращает an iterator, которая является то, что позволяет ему работать в обмен на петлю; не путайте это с помощью Object.entries(), который возвращает массив пар ключ-значение.

+2

Это гораздо лучший ответ, чем принятый! – trusktr

+1

Я думаю, что это решение лучше, чем forEach один ... Он использует nomral для ... синтаксиса цикла, и вам не нужно использовать отдельную функцию. Другими словами, это синтаксически лучше. Кажется, что ФП этого хотела. – u8y7541

+1

'entries()' возвращает пустой объект: '{}'. Любая идея, почему это было бы? Мой массив - это массив объектов. –

1

Как об этом

let numbers = [1,2,3,4,5] 
numbers.forEach((number, index) => console.log(`${index}:${number}`)) 
Смежные вопросы