Вопрос по javascript – Получить счетчик / индекс цикла, используя для… синтаксиса в JavaScript

178
Caution:

question still applies to for…of loops.> Don't use for…in to iterate over an Array, use it to iterate over the properties of an object. That said, this

Я понимаю что основноеfor…in Синтаксис в JavaScript выглядит следующим образом:

<code>for (var obj in myArray) {
    // ...
}
</code>

Но как мне получить петлюcounter/index?

I know I could probably do something like:
<code>var i = 0;
for (var obj in myArray) {
    alert(i)
    i++
}
</code>
Or even the good old:
<code>for (var i = 0; 1 < myArray.length; i++) {
    var obj = myArray[i]
    alert(i)
}
</code>

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

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

In Python it's easy:
<code>for i, obj in enumerate(myArray):
    print i
</code>
Это массив, а не объект, верно? Так,alert(obj)? Rocket Hazmat
Не использовать для ... в массивах. И в любом случае, он перебирает имена свойств, а не значения свойств. Felix Kling

Ваш Ответ

8   ответов
315

for…in перебирает имена свойств, а не значения, и делает такв неуказанном порядке (да, даже после ES6). Вы не должны использовать его для перебора массивов. Для них есть ES5 & # x2019; sforEach метод, который передает значение и индекс функции, которую вы ему даете:

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 & # x2019; sArray.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 & # X2013; перечисление свойств & # x2013; вам понадобится дополнительный счетчик.Object.keys(obj).forEach может работать, но включает толькоown свойства;for…in включает перечисляемые свойства в любом месте цепочки прототипов.

Я не знал, что это возможноmyArray.forEach(function (value, *i*) (акцент мой). Это потрясающе. Я знал, что должен быть лучший способ, чем этоmyArray.indexOf(value) мусор, который я делал. +1.
@quantumpotato:letсvars с областью блока.constс неизменны.
Фактически, obj будет индексом массива, но нет никакой гарантии, что он в порядке и не будет включать в себя другие имена свойств.
О хорошо Я был сбит с толку. Я думал, что JavaScript for-in был таким же, как Python. Спасибо за разъяснения. hobbes3
Вам не нужно делать var i = 0, потому что давайте неизменны?
9

Как насчет этого

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

кудаarray.forEach этот метод имеетindex параметр, который является индексом текущего элемента, обрабатываемого в массиве.

лучший ответ здесь
0

Это моя версия составного итератора, который выдает индекс и значение любой переданной функции генератора с примером (медленного) простого поиска:

const eachWithIndex = {
  *[Symbol.iterator](iterator) {
    let i = 0
    for(let val of iterator) {
      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[Symbol.iterator](primes)) {
  console.log(i, prime)
  if (i === 100) break
}

12

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

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

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

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
}
Никогда не делай(var i=0; i<a.length; i++) как впустую потраченные ресурсы. использование(var i=0, var len = a.length; i<len; i++)
лучшие практики - лучшие практики!
KISS, Если вы пишете циклы там, где это действительно нужно, вы либо делаете что-то не так, либо у вас есть более веский аргумент в пользу его необходимости, чем "наилучшая практика". Да, это стандартная практика, но не для общей оптимизации производительности, а только для микрооптимизации.
@FelixSanz: тратить ресурсы? Ни за что. Это преждевременная микрооптимизация, которая вряд ли когда-либо необходима, иvar i=0; i<a.length; i++) это стандартный шаблон цикла, который в любом случае оптимизируется каждым приличным движком javascript.
ПОЦЕЛУЙ применяется везде.Premature optimisation это антипрактика.
15

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

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

arr - ARRAY, obj - KEY of current element, i - СЧЕТЧИК / ИНДЕКС

Notice: методkeys() недоступно для версии IE & lt; 9, вам следует использоватьPolyfill код. https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

Я предлагаю: используйте счетчик, увеличивайте его в цикле.
Чем больше объект, тем медленнее это будет. Это не масштабируется.
Это бессмысленно медленно и сложно, потому чтоvar i = 0; а такжеi++; короче и эффективнее. Кроме того, он не работает для перечисляемых свойств, которые не являются собственными свойствами.
@trusktr: И если это требуется & # x2026; Вы все еще не должны использовать это. Просто измените счетчик, когда вы измените коллекцию. Если это не обязательно должно быть на месте, вместо этого сделайте хорошее функциональное преобразование.
В дополнение к mayankcpdixit, используйте вместо этого счетчик, потому что indexOf может оказать негативное влияние на производительность.
96

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

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

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

Я думаю, что это решение лучше, чем forEach ... Оно использует номинал для ... синтаксиса цикла, и вам не нужно использовать отдельную функцию. Другими словами, это синтаксически лучше. ОП, похоже, хотел этого.
entries() возвращает пустой объект:{}, Есть идеи, почему это будет? мойarray это массив объектов.
Это должно быть сделано, Джошуа - объект является итератором, объект сnext() метод, который будет возвращать последующие записи в массиве каждый раз, когда он вызывается. В нем нет (видимых) данных; вы получаете данные в базовом объекте, вызываяnext(), который из-за делает за кулисами. cc @tonyg
@JoshuaPinter попробуйObject.entries(array) вместоarray.entries()
Это гораздо лучший ответ, чем принятый!
5

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

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

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

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

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

0

Здесь функция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)

Хорошая вещь с генераторами состоит в том, что они ленивы и могут принять результат другого генератора в качестве аргумента.

Похожие вопросы