Получить счетчик/индекс цикла, используя для… синтаксиса в JavaScript
Внимание:
Вопрос по-прежнему относится к циклам for…of
>. Не используйте for…in
для итерации по массиву, используйте его для итерации по свойствам объекта. Тем не менее, это
Я понимаю, что основной синтаксис for…in
в JavaScript выглядит следующим образом:
for (var obj in myArray) {
// ...
}
Но как мне получить счетчик/индекс цикла?
Я знаю, что мог бы сделать что-то вроде:
var i = 0;
for (var obj in myArray) {
alert(i)
i++
}
Или даже старый добрый
for (var i = 0; i < myArray.length; i++) {
var obj = myArray[i]
alert(i)
}
Но я бы предпочел использовать более простой цикл for-in
. Я думаю, что они выглядят лучше и имеют больше смысла.
Есть ли более простой или более элегантный способ?
В Python это просто:
for i, obj in enumerate(myArray):
print i
Ответы
Ответ 1
for…in
перебирает имена свойств, а не значения, и делает это в неопределенном порядке (да, даже после ES6). Вы не должны использовать его для перебора массивов. Для них есть метод ES5s forEach
который передает и значение, и индекс в функцию, которую вы ему передаете:
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
Или ES6s 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);
}
демонстрация
Если вы действительно имели в виду for…in
перечислении свойств - вам понадобится дополнительный счетчик. Object.keys(obj).forEach
может работать, но включает только собственные свойства; for…in
включает перечислимые свойства в любом месте цепочки прототипов.
Ответ 2
В ES6 полезно использовать for-loop.
Вы можете получить индекс для такого типа
for (let [index, val] of array.entries()) {
// your code goes here
}
Обратите внимание, что Array.entries()
возвращает итератор, что позволяет ему работать в цикле for-loop; не путайте это с Object.entries(), который возвращает массив пар ключ-значение.
Ответ 3
Решение для небольших массивов массивов:
for (var obj in arr) {
var i = Object.keys(arr).indexOf(obj);
}
arr - ARRAY,
obj - КЛЮЧ текущего элемента,
i - COUNTER/INDEX
Примечание. Ключи методов() недоступны для версии IE и 9, вы должны использовать код Polyfill.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Ответ 4
Как насчет этого
let numbers = [1,2,3,4,5]
numbers.forEach((number, index) => console.log('${index}:${number}'))
Где array.forEach
этого метода есть параметр index
который является индексом текущего элемента, обрабатываемого в массиве.
Ответ 5
In-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
}
Ответ 6
Как говорили другие, вы не должны использовать for..in для итерации по массиву.
for ( var i = 0, len = myArray.length; i < len; i++ ) { ... }
Если вам нужен более чистый синтаксис, вы можете использовать forEach:
myArray.forEach( function ( val, i ) { ... } );
Если вы хотите использовать этот метод, убедитесь, что вы включили прокладку ES5, чтобы добавить поддержку старых браузеров.
Ответ 7
Здесь функция eachWithIndex
которая работает с чем угодно итеративным.
Вы также можете написать аналогичную функцию eachWithKey
которая работает с объектами, использующими 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)
Хорошая вещь с генераторами - то, что они ленивы и могут взять другой результат генератора в качестве аргумента.
Ответ 8
Это моя версия составного итератора, который возвращает индекс и любое переданное значение функции генератора с примером (медленного) простого поиска:
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
}