在for-of循环中如何访问ES6数组元素的索引?

443

我们可以使用 for-of 循环访问数组元素:

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

如何修改此代码以访问当前索引?我想使用for-of语法实现,而不是forEach或for-in。

12个回答

676
使用Array.prototype.keys

for (const index of ["a", "b", "c", "d", "e"].keys()) {
  console.log(index);
}

如果你想同时访问键和值,你可以使用 Array.prototype.entries()解构

for (const [index, value] of ["a", "b", "c", "d", "e"].entries()) {
  console.log(index, value);
}


128
有人可能会想知道,我尝试了使用.entries()for-of循环,结果比起使用.forEach()循环慢了两倍。 https://jsperf.com/for-of-vs-foreach-with-index - user6269864
3
如果你想要最快的速度,在ES中使用"反向循环",可以参考这篇文章:https://www.incredible-web.com/blog/performance-of-for-loops-with-javascript/。 - nimo23
4
很遗憾,我需要在嵌套循环内部使用yield关键字时退出循环。无法使用forEach,因为该函数对于yield关键字会创建作用域问题。但是,基于我的使用情况,我需要访问索引,所以……我猜只能使用基本的旧式“;;”循环了。 - Kyle Baker
2
@KyleBaker,使用.entries()的for-of循环有什么问题吗? - Michał Perłakowski
1
不要使用反向循环,可以缓存长度 https://jsperf.com/reverse-loop-vs-cache。 对于可迭代处理,for-of非常有用,当您能够在RAM中创建大数组而不创建流时进行处理。在这种情况下,循环速度不会成为瓶颈,因为您将具有I/O延迟。 - x'ES
显示剩余5条评论

400

Array#entries 返回索引和值,如果您都需要:

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

}

4
使用 TypeScript 时,出现错误信息 'TS2495: Type IterableIterator is not an array type or a string type'。看起来这个问题将会得到解决:https://github.com/Microsoft/TypeScript/pull/12346。 - user89862
2
同时,不支持Internet Explorer浏览器。 - Sámal Rasmussen
1
不好。例如使用 document.styleSheets[0].cssRules.entries() 或者 document.styleSheets.entries() 以及其他许多可迭代的 DOM 结构都会抛出错误。仍然需要使用 lodash 中的 _.forEach() - Steven Pribilinskiy
2
@Steven:如果您不需要索引,您可以直接使用 for (var value of document.styleSheets) {}。如果您确实需要索引,您可以先通过 Array.from 将值转换为数组:for (let [index, value] of Array.from(document.styleSheets)) {} - Felix Kling
1
太好了!Array.from就是胜利。 - Steven Pribilinskiy
显示剩余2条评论

127

在这个充满新奇本地函数的世界里,我们有时会忘记基础。

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

清晰、高效,而且你仍可以使用break语句来终止循环。更棒的是,你还可以通过i--从后往前开始遍历!

额外提示:如果在循环中频繁使用某个值,你可能希望在循环顶部使用const value = arr[i];来获得一个易于阅读的引用。


3
顺便提一下,条件应该像这样 -> for (let i = 0; i < arr.length; i++),不要加上 (-1),否则它将无法循环遍历数组的所有元素。 - Combine
7
您仍然可以打断一个for-of循环,而且for (let [index, value] of array.entries())要容易阅读得多。倒序遍历只需添加.reverse()即可。 - user2493235
9
我认为这是对这个问题一个完全可以接受的回答。虽然它可能不会成为被采纳的答案,但已经帮助了几十个或更多搜索该问题的人。这就是 SO 的用途。 - Danoram
12
简单的 for 循环比使用 for of array.entries() 快约8倍。https://jsbench.me/6dkh13vqrr/1 - Henrique Bruno
3
很遗憾,这不能与异步代码一起使用(根据我的经验,只有在使用for...of循环的时候才会出现这种情况)。这个问题存在是有原因的... - lawrence-witt
显示剩余7条评论

23
在一个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);
}


11

如果您需要索引(index),您也可以自己处理它,但如果您需要键(key),这种方法无效。

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

  i++;
}

6

另一个方法可以使用Array.prototype.forEach()作为

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


4
在HTML/JS上下文中,在现代浏览器中,除了数组以外,我们还可以使用[Iterable].entries()来处理其他可迭代对象:
for(let [index, element] of document.querySelectorAll('div').entries()) {

    element.innerHTML = '#' + index

}

是的,这个可以工作,而其他由@Steven Pribilinskiy提到的DOM方法返回的对象没有entries方法。 - matanster

4

在循环之前创建一个变量并赋一个整数值。

let index = 0;

然后在循环范围内使用加法赋值运算符

index += 1;

就这样,查看下面的代码片段示例。

let index = 0;
for (const j of [1, 2, 3, 4, 5]) {
  console.log('index ',index);
  index += 1;
}


2

你可以尝试在for...循环中使用indexOf方法

let arrData = [15, 64, 78]
for (const data of arrData) {
  console.log("data value", data, "index of data ", arrData.indexOf(data));
}


这个只适用于唯一元素,并且具有O(n^2)的复杂度 :( - Jiří

2

对于那些使用的不是Array或类似数组的对象,你可以轻松地构建自己的可迭代对象,这样你仍然可以像处理length属性的localStorage一样使用for of语句:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接