主题
for...in
和 for...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...in | for...of |
---|---|---|
遍历对象 | 可枚举属性 | 可迭代对象 |
遍历值 | 属性名(key) | 元素值(value) |
原型链属性 | 会遍历 | 不会遍历 |
适用对象 | 普通对象 | 数组、字符串、Set、Map、自定义迭代器 |
可否中断 | 可以通过 break | 可以通过 break |
是否可配合 await | 否 | 可与 for await...of 搭配使用 |