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


228

Ми можемо отримати доступ до елементів масиву за допомогою циклу for-of:

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 Приємно знати, використовуйте "reversed for-loop", якщо ви хочете мати найшвидший в es: incredible-web.com/blog/…
nimo23

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

2
@KyleBaker А що не так з циклом for-of .entires()?
Michał Perłakowski

1
Замість зворотного циклу ви можете кешувати довжину jsperf.com/reverse-loop-vs-cache . Корисна для ітерабельної обробки, коли ви можете обробляти потік, не створюючи великих масивів в ОЗП. Швидкість циклу не буде вузьким місцем, оскільки у вас буде затримка вводу / виводу в таких випадках.
x'ES

289

Array#entries повертає індекс і значення, якщо вам потрібно і те, і інше:

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

}

3
З TypeScript: 'TS2495: Type 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 Хороший улов! Я оновив свою відповідь, щоб відобразити вашу замітку.
chris

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

3
Я думаю, що це цілком прийнятна відповідь на це питання. Це ніколи не буде прийнятою відповіддю, але це допомогло кілька десятків людей і більше, які шукали це питання. Це те, для чого SO.
Данорам

3

в контексті html / js, в сучасних браузерах, з іншими ітерабельними об'єктами, крім Arrays, ми також могли використовувати [Iterable] .entries ():

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

    element.innerHTML = '#' + index

}

Так, це працює, тоді як інші, згадані вище @Steven Pribilinskiy, інші методи DOM повертають об'єкти, які не мають entriesдля них методу.
matanster

3

У for..ofциклі ми можемо досягти цього за допомогою array.entries(). array.entriesповертає новий об’єкт ітератора масиву. Об'єкт ітератора знає, як отримати доступ до елементів з ітерабельного одночасно, зберігаючи його поточне положення у цій послідовності.

Коли 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петлю не afor...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
Це займає час O (n ^ 2).
Гаррі

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