entries() 返回 Array Iterator 对象,按索引升序产出 [index, value] 二元数组

entries() 返回的是什么类型的迭代器
当你调用数组的 entries() 方法时,它给你的并不是一个普通的数组,而是一个专门的 Array Iterator 对象。这个迭代器会严格按照索引从低到高的顺序,一个接一个地产出形如 [index, value] 的二元数组。这里有个常见的“坑”:因为它产出的是数组结构,所以你不能像处理对象那样,直接用 for...in 去遍历,或者试图不解构就获得数据。
举个例子,如果写下 for (const item of arr.entries()) { console.log(item); },控制台打印出的会是 [0, “a”]、[1, “b”] 这样的数组。若你误以为 item 是个对象,去访问 item.key 或 item.value,结果只能是 undefined。
正确解构 entries() 的每一项
想优雅地拿到索引和值?窍门在于使用数组解构语法,精准匹配它产出的二元数组结构。业内最通用、最推荐的写法是这样的:
for (const [index, value] of arr.entries()) {
console.log(index, value);
}
当然,也存在其他合法的写法,不过从代码的简洁性和可读性角度看,就不太推荐了:
for (const pair of arr.entries()) { const [i, v] = pair; }—— 多了一层解构,显得有些冗余。const iter = arr.entries(); console.log(iter.next().value);—— 这是手动调用迭代器的next()方法,通常只在需要精细控制迭代过程(比如中断或条件推进)时才会用到。
还有一点需要注意:别尝试写成 for (const {0: i, 1: v} of arr.entries()) 这种形式。对象解构在这里不适用,因为它无法直接展开数字属性名。虽然可以先把数组项转成对象,但实在没那个必要,徒增复杂度。
entries() 和 for...of / Array.from / 扩展运算符的兼容性
好消息是,entries() 返回的迭代器完全遵循 Ja vaScript 的迭代协议,可以被所有原生支持该协议的语法轻松“消费”。主流的用法包括:
for...of循环:这是最常用、最直观的方式,适合直接遍历处理。Array.from(arr.entries()):这会把所有[index, value]对一次性收集起来,生成一个形如[[0,a], [1,b], ...]的二维数组。当你需要把结果缓存下来,供后续多次查询或处理时,这个方法很管用。[...arr.entries()]:扩展运算符能达到和Array.from一样的效果,而且写法更简洁,是当下更流行的风格。
这里得提个性能上的小建议:如果只是单次遍历,并且不需要保留索引之外的复杂信息,那么使用 for...of 配合解构是最轻量、最高效的选择。反之,如果后续可能还需要多次访问这些键值对,那就用 Array.from() 转换成数组存起来更稳妥,毕竟 entries() 返回的迭代器只能被消费一次。
entries() 在稀疏数组和类数组对象上的行为差异
entries() 在面对不同类型的“数组”时,表现并不完全一致。
对于标准的 Ja vaScript 数组,即便是存在空位(hole)的稀疏数组,entries() 也会忠实地为每一个索引位置产出一项,空位则会以 [index, undefined] 的形式呈现。
然而,它的“能力范围”并不覆盖**类数组对象**,比如函数内的 arguments 对象,或者 DOM 操作返回的 NodeList。这些对象本身并没有 entries 方法。要想对它们进行类似数组的索引-值遍历,一个安全的做法是先将其转化为真正的数组:
for (const [i, el] of Array.from(document.querySelectorAll('div')).entries()) {
// 现在可以安全操作了
}
当然,理论上你也可以用 Array.prototype.entries.call(nodeList) 这种方式来“借用”方法,但这么做代码可读性会大打折扣,一般不推荐在项目中使用。
