Доступ к индексу элемента массива ES6 внутри цикла for-of


228

Мы можем получить доступ к элементам массива, используя цикл for:

for (const j of [1, 2, 3, 4, 5]) {
  console.log(j);
}

Как я могу изменить этот код для доступа к текущему индексу тоже? Я хочу добиться этого с помощью синтаксиса for-of, ни forEach, ни for-in.

Ответы:


351

Используйте Array.prototype.keys:

for (const index of [1, 2, 3, 4, 5].keys()) {
  console.log(index);
}

Если вы хотите получить доступ и к ключу, и к значению, вы можете использовать Array.prototype.entries()с деструктуризацией :

for (const [index, value] of [1, 2, 3, 4, 5].entries()) {
  console.log(index, value);
}


64
В случае , если кто - то чудеса, я испытал for-ofс , .entries()и это в два раза медленнее по сравнению с .forEach(). jsperf.com/for-of-vs-foreach-with-index

1
@ K48 приятно знать, используйте «обратный цикл», если вы хотите иметь самый быстрый в es: incredible-web.com/blog/…
— nimo23

3
К сожалению, мне нужно уступить из вложенного цикла. Невозможно использовать forEach, поскольку функция создает проблемы с областью действия для yieldключевого слова. Но мне нужен доступ к индексу для моего варианта использования, так что ... ;;я думаю , что это простой старый цикл.
— Кайл Бейкер

2
@KyleBaker А что не так с циклом for .entires()?
— Михал Перлаковский

1
Вместо обратного цикла вы можете кешировать длину jsperf.com/reverse-loop-vs-cache . Полезно для итеративной обработки, когда вы можете обрабатывать поток без создания больших массивов в оперативной памяти. Скорость цикла не будет узким местом, так как в таких случаях у вас будет задержка ввода / вывода.
— x'ES

289

Array#entries возвращает индекс и значение, если вам нужны оба:

for (let [index, value] of array.entries()) {

}

3
С TypeScript: «TS2495: Тип IterableIterator не является типом массива или типом строки». Похоже, это будет решено: github.com/Microsoft/TypeScript/pull/12346
— Йоханнес

2
Также Internet Explorer не поддерживается.
— Сэмми

1
Не хорошо. Выдает ошибку, например, с помощью document.styleSheets[0].cssRules.entries()даже или, document.styleSheets.entries()возможно, многих других итеративных структур DOM. Еще надо использовать _.forEach()сlodash
— Стивен Прибилинский

2
@ Steven: Если вам не нужен индекс, вы можете просто сделать for (var value of document.styleSheets) {}. Если вам нужен индекс вы можете преобразовать значение в массив первым с помощью Array.from: for (let [index, value] of Array.from(document.styleSheets)) {}.
— Феликс Клинг

1
Это мило! Array.fromтакое FTW
— Стивен Прибилинский

28

В этом мире ярких новых нативных функций мы иногда забываем основы.

for (let i = 0; i < arr.length; i++) {
    console.log('index:', i, 'element:', arr[i]);
}

Чисто, эффективно, и вы все еще можете breakпетлю. Бонус! Вы также можете начать с конца и вернуться назад i--!

Дополнительное примечание: если вы много используете значение в цикле, вы можете сделать это const value = arr[i];в верхней части цикла для удобного и удобного чтения.


1
Ага. Хороший, понятный и простой. О, и так у вас есть супер простой способ доступа к ключу / индексу массива.
— Объединить

2
Кстати, условие должно выглядеть так -> для (пусть i = 0; i <arr.length; i ++) без (-1), иначе оно не будет зацикливаться во всех элементах массива.
— Объединить

1
@Combine Хороший улов! Я обновил свой ответ, чтобы отразить вашу заметку.
— Крис

4
Вы все еще можете и гораздо легче читать. Вернуться назад так же просто, как добавить . breakfor-offor (let [index, value] of array.entries()).reverse()
— Найджел Б. Пек

3
Я думаю, что это вполне приемлемый ответ на этот вопрос. Это никогда не будет принятым ответом, но это помогло нескольким дюжинам людей или больше, которые искали этот вопрос. Вот для чего ТАК.
— Данорам

3

в контексте html / js, в современных браузерах, с другими итерируемыми объектами, кроме массивов, мы могли бы также использовать [Iterable] .entries ():

for(let [index, element] of document.querySelectorAll('div').entries()) {

    element.innerHTML = '#' + index

}

Да, это работает, тогда как другие, упомянутые выше @Steven Прибилинским, другие методы DOM возвращают объекты, у которых нет entriesметода для них.
— Матенстер

3

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

При next()вызове метода на итераторе генерируются пары ключ-значение. В этих парах ключ-значение индекс массива является ключом, а элемент массива является значением.

let arr = ['a', 'b', 'c'];
let iterator = arr.entries();
console.log(iterator.next().value); // [0, 'a']
console.log(iterator.next().value); // [1, 'b']

for..ofЦикл в основном конструкция , которая потребляет итератор и петлю по всем элементам ( с использованием итератора под капотом). Мы можем объединить это с array.entries()помощью следующего способа:

array = ['a', 'b', 'c'];

for (let indexValue of array.entries()) {
  console.log(indexValue);
}


// we can use array destructuring to conveniently
// store the index and value in variables
for (let [index, value] of array.entries()) {
   console.log(index, value);
}


3

Вы также можете обрабатывать индекс самостоятельно, если вам нужен индекс , он не будет работать, если вам нужен ключ .

let i = 0;
for (const item of iterableItems) {
  // do something with index
  console.log(i);

  i++;
}

0

Для тех , кто использует объекты , которые не являются Arrayили даже массив , как вы можете создать свою собственную итерацию легко , так что вы все еще можете использовать for ofдля таких вещей , как , localStorageкоторые на самом деле есть только length:

function indexerator(length) {
    var output = new Object();
    var index = 0;
    output[Symbol.iterator] = function() {
        return {next:function() {
            return (index < length) ? {value:index++} : {done:true};
        }};
    };
    return output;
}

Тогда просто введите номер:

for (let index of indexerator(localStorage.length))
    console.log(localStorage.key(index))

0

ES6 for...in

for(const index in [15, 64, 78]) {                        
    console.log(index);
}

5
Вопрос задается о for...ofпетле, а не оfor...in
— Авраам Эрнандес

3
for...inявляется частью оригинальной спецификации ECMAScript (то есть "es1"). Также обратите внимание, что for...inон предназначен для перебора свойств объекта. Хотя он может перебирать массивы, он может делать это не в ожидаемом порядке. См. Больше в документации MDN
— Боаз

0

Другой подход может быть использован Array.prototype.forEach()как

Array.from({
  length: 5
}, () => Math.floor(Math.random() * 5)).forEach((val, index) => {
  console.log(val, index)
})


-6
var fruits = ["apple","pear","peach"];
for (fruit of fruits) {
    console.log(fruits.indexOf(fruit));
    //it shows the index of every fruit from fruits
}

цикл for проходит через массив, а свойство indexof принимает значение индекса, соответствующего массиву. У этого метода есть некоторые недостатки с числами, поэтому используйте фрукты


2
Это займет О (п ^ 2) время.
— Гарри

3
В случаях, когда производительность не важна, это все еще не дает все правильные индексы, когда есть повторяющиеся фрукты. Например, для ["apple", "apple", "pear"]приведенных индексов 0, 0, 2вместо 0, 1, 2.
— Trichoplax
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.