Skip to content

for...infor...of 的区别

一、遍历的对象不同

  • for...in:遍历对象的可枚举属性(key)
  • for...of:遍历可迭代对象的值(value)

二、适用场景对比

for...in —— 常用于遍历对象的属性

js
const obj = { a: 1, b: 2, c: 3 }

for (let key in obj) {
  console.log(key, obj[key])
}
// 输出:
// a 1
// b 2
// c 3

⚠️ 会遍历原型链上的可枚举属性:

js
obj.__proto__.d = 4

for (let key in obj) {
  console.log(key, obj[key])
}
// 输出包含 d:a 1, b 2, c 3, d 4

✔️ 推荐搭配 hasOwnProperty() 使用,过滤原型上的属性:

js
for (let key in obj) {
  if (obj.hasOwnProperty(key)) {
    console.log(key, obj[key])
  }
}

for...of —— 用于遍历可迭代对象

包括:字符串、数组、Set、Map 等。

js
for (let val of 'abc') {
  console.log(val)
}
// 输出:a b c

for (let val of ['a', 'b', 'c']) {
  console.log(val)
}
// 输出:a b c

三、让普通对象支持 for...of

方法一:手动实现 [Symbol.iterator]

js
const range = {
  from: 1,
  to: 3,
  [Symbol.iterator]() {
    let current = this.from
    return {
      next: () =>
        current <= this.to
          ? { value: current++, done: false }
          : { done: true }
    }
  }
}

for (let val of range) {
  console.log(val)
}
// 输出:1 2 3

方法二:使用生成器函数简化实现

js
const range = {
  from: 1,
  to: 3,
  *[Symbol.iterator]() {
    for (let i = this.from; i <= this.to; i++) {
      yield i
    }
  }
}

for (let val of range) {
  console.log(val)
}
// 输出:1 2 3

查看迭代器过程:手动调用 next()

js
const iterator = range[Symbol.iterator]()
console.log(iterator.next()) // { value: 1, done: false }
console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { value: undefined, done: true }

四、总结对比表格

对比项for...infor...of
遍历对象可枚举属性可迭代对象
遍历值属性名(key)元素值(value)
原型链属性会遍历不会遍历
适用对象普通对象数组、字符串、Set、Map、自定义迭代器
可否中断可以通过 break可以通过 break
是否可配合 await可与 for await...of 搭配使用