跳到主要内容

遍历方法对比 for-of 和 for-in

在 JavaScript 中,for-offor-in 是两种常用的循环方法,用于遍历不同类型的数据结构。了解它们的区别和使用场景对于编写高效且易于维护的代码至关重要。

遍历对象

for-of

for-of 循环用于遍历可迭代对象,如数组、字符串、Map、Set 等。尝试使用 for-of 遍历普通对象会导致错误,因为普通对象不可迭代。

const obj = {
a: 1,
b: [],
c: function () {},
};

for (const key of obj) {
console.log(key);
}
// 出错:
// Uncaught TypeError: obj is not iterable

for-in

for-in 循环用于遍历对象的可枚举属性,包括继承的属性。它适用于普通对象,但需要注意它也会遍历对象原型链上的属性。

const obj = {
a: 1,
b: [],
c: function () {},
};

for (const key in obj) {
console.log(key);
}
// 输出:
// a
// b
// c

遍历数组

for-of

for-of 适用于遍历数组中的值,语法简洁且易于理解。

const arr = [3, 5, 7];

for (const value of arr) {
console.log(value);
}
// 输出:
// 3
// 5
// 7

for-in

for-in 遍历数组的索引,而不是值。这在某些情况下可能不符合预期,特别是当数组被扩展或修改时。

const arr = [3, 5, 7];

for (const index in arr) {
console.log(index);
}
// 输出:
// 0
// 1
// 2

总结

  • for-of 无法遍历不可迭代对象。
  • for-of 遍历的是值,而 for-in 遍历的是键。

可迭代对象

Array.prototype.entries() - JavaScript | MDN

entries() 方法返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对。

const arr = [1, 2, 3, 4, 5];
const iterator = arr.entries();

console.log(iterator.next().value); // [0, 1]

让 for-of 遍历可迭代对象

for-of 通过判断对象是否实现了 Symbol.iterator 来确定对象是否是可迭代的。对于不可迭代的对象,可以在其原型上添加 Symbol.iterator 方法,使其变为可迭代对象。

const obj = {
0: 1,
1: 2,
2: 3,
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator],
};

for (const value of obj) {
console.log(value);
}
// 输出:
// 1
// 2
// 3

使用 Array.from

Array.from 方法可以将类数组对象转换为数组,从而使其可被 for-of 遍历。

const obj = {
0: 1,
1: 2,
2: 3,
length: 3,
};

for (const value of Array.from(obj)) {
console.log(value);
}
// 输出:
// 1
// 2
// 3

next 方法的运行原理

next 方法用于手动迭代迭代器对象,返回包含 valuedone 属性的对象。

const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();

const newArr = [];
let item;
while (!(item = iterator.next()).done) {
newArr.push(item.value);
}

console.log(newArr); // [1, 2, 3]

二维数组的排序

使用 for-ofArray.prototype.entries() 方法,可以方便地遍历和排序二维数组中的每个子数组。

const twoDArray = [
[56, 34],
[123, 123, 12, 1],
[12, 3, 213],
];

function sort2DArray(arr) {
for (const [index, subArray] of arr.entries()) {
arr[index].sort((a, b) => a - b);
}
return arr;
}

console.log(sort2DArray(twoDArray));
// 输出:
// [ [34, 56],
// [1, 12, 123, 123],
// [3, 12, 213] ]

链接

了解更多信息,请访问 Array.prototype.entries() - JavaScript | MDN

实现可迭代对象

要使一个对象成为可迭代对象,可以在其原型上添加 Symbol.iterator 方法。例如,将一个类数组对象转换为可迭代对象:

const iterableObj = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: Array.prototype[Symbol.iterator],
};

for (const value of iterableObj) {
console.log(value);
}
// 输出:
// a
// b
// c

通过这种方式,可以利用 for-of 循环遍历原本不可迭代的对象。

Array.prototype.entries() 方法详解

entries() 方法返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键/值对。

const arr = [1, 2, 3, 4, 5];
const iterator = arr.entries();

console.log(iterator.next().value); // [0, 1]
console.log(iterator.next().value); // [1, 2]

这个方法在需要同时访问数组的索引和值时非常有用,尤其是在使用 for-of 循环时。

const arr = ['x', 'y', 'z'];

for (const [index, value] of arr.entries()) {
console.log(`${index}: ${value}`);
}
// 输出:
// 0: x
// 1: y
// 2: z

总结

for-offor-in 各有其适用场景。for-of 更适合遍历可迭代对象的值,而 for-in 则用于遍历对象的键。通过理解它们的差异和适用场景,可以编写出更高效和可读性更强的代码。

链接

更多信息,请参考 Array.prototype.entries() - JavaScript | MDN

实现二维数组排序的示例

以下是一个使用 for-ofentries() 方法对二维数组进行排序的完整示例:

const twoDArray = [
[56, 34],
[123, 123, 12, 1],
[12, 3, 213],
];

function sort2DArray(arr) {
for (const [index, subArray] of arr.entries()) {
arr[index].sort((a, b) => a - b);
}
return arr;
}

console.log(sort2DArray(twoDArray));
// 输出:
// [ [34, 56],
// [1, 12, 123, 123],
// [3, 12, 213] ]

在这个示例中,sort2DArray 函数通过遍历每个子数组并对其进行排序,实现了对整个二维数组的排序。

注意事项

  • 使用 for-in 循环时,需注意它会遍历对象的所有可枚举属性,包括继承的属性。
  • for-of 只能用于遍历可迭代对象,普通对象需手动添加 Symbol.iterator 方法才能使用 for-of
  • Array.prototype.entries() 方法在需要同时访问数组的索引和值时非常有用。

链接

了解更多内容,请访问 Array.prototype.entries() - JavaScript | MDN