for…of和for…in的区别?

在JavaScript中,for...offor...in是两种不同的循环语句,它们看起来相似,但遍历的对象和内容有本质区别。混用它们是一个常见错误,理解其差异是编写正确循环代码的前提。

for…in循环:遍历对象的可枚举属性

for...in循环遍历一个对象除Symbol以外的所有可枚举属性,包括从其原型链上继承的属性。它的设计初衷是遍历对象的“键”(属性名)。

const obj = { a: 1, b: 2 };
Array.prototype.customProp = 'oops';

for (let key in obj) {
  console.log(key); // 依次输出 'a', 'b'
}

const arr = ['x', 'y'];
for (let key in arr) {
  console.log(key); // 依次输出 '0', '1', 'customProp'
}

如你所见,当遍历数组时,for...in循环输出的是索引字符串(‘0’, ‘1’),而不是数组元素。更糟糕的是,如果数组原型被扩展了自定义的可枚举属性(如例子中的customProp),它也会被遍历出来。因此,使用for...in遍历数组通常不是好主意,它更适合遍历普通对象。为了避免遍历到继承的属性,通常需要在循环内部使用hasOwnProperty进行检查。

for…of循环:遍历可迭代对象的值

for...of是ES6引入的,它遍历的是可迭代对象的值。可迭代对象是指实现了[Symbol.iterator]方法的对象,如数组、字符串、Map、Set、NodeList等。

const arr = ['x', 'y'];
for (let value of arr) {
  console.log(value); // 依次输出 'x', 'y'
}

const str = 'hi';
for (let char of str) {
  console.log(char); // 依次输出 'h', 'i'
}

for...of直接获取迭代器产生的值,而不是键。对于数组,它遍历元素;对于字符串,它遍历字符;对于Map,它遍历键值对数组[key, value]。它不会遍历原型链上的属性,只关心迭代器定义的值序列。

核心差异总结

for...in循环遍历的是对象的属性名(键),操作的是对象的可枚举属性列表,包括继承的属性。它适用于普通对象,但不保证顺序(虽然现代引擎通常按插入顺序,但并非所有情况)。

const obj = { 10: 'a', 2: 'b', 1: 'c' };
for (let key in obj) {
  console.log(key); // 可能输出 '1', '2', '10' (注意键会被转换为字符串)
}

for...of循环遍历的是可迭代对象的,操作的是对象的迭代器定义的值序列。它适用于数组、字符串等集合,且保证顺序。普通对象默认不是可迭代的,因此不能直接用for...of遍历。

// 普通对象使用 for...of 会报错
const plainObj = { a: 1, b: 2 };
// for (let val of plainObj) {} // TypeError

简而言之,当你需要遍历对象的属性键时,用for...in(并配合hasOwnProperty)。当你需要遍历数组元素、字符串字符或其他集合的值时,用for...of。在现代JavaScript中,对于数组遍历,for...of或高阶函数(forEach, map)通常是更安全、更清晰的选择。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容