让对象支持数组解构赋值
通过实现迭代器协议,让普通对象支持数组解构语法
问题
如何让 var [a, b] = {a: 1, b: 2} 这样的解构赋值成功?
解答
问题分析
直接对对象使用数组解构会报错:
const obj = {
a: '1',
b: '2',
}
const [a, b] = obj // TypeError: obj is not iterable
错误提示对象不可迭代。数组和 Map 等内置类型默认是可迭代的,而普通对象不是。
可迭代协议
要成为可迭代对象,需要实现 @@iterator 方法,即对象上要有一个 [Symbol.iterator] 属性,它是一个函数,返回一个迭代器对象。
验证数组确实有这个方法:
const array = [1, 2, 3]
const iterator = array[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 }
迭代器对象的 next() 方法返回 { value, done },其中 value 是当前值,done 表示是否迭代完成。
数组解构的本质
const array = [1, 2, 3]
var [a, b, c] = array
// 本质上等同于
const iterator = array[Symbol.iterator]()
var a = iterator.next().value
var b = iterator.next().value
var c = iterator.next().value
解决方案
给对象添加 [Symbol.iterator] 方法:
const obj = {
a: '1',
b: '2',
[Symbol.iterator]() {
let index = 0
const keys = Object.keys(this)
return {
next: () => {
if (index < keys.length) {
return {
done: false,
value: this[keys[index++]]
}
}
return {
done: true,
value: undefined
}
}
}
}
}
const [a, b] = obj
console.log(a, b) // '1' '2'
现在对象也可以用 for...of 遍历:
for (let i of obj) {
console.log(i)
}
// '1'
// '2'
关键点
- 数组解构本质是调用对象的
[Symbol.iterator]方法获取迭代器,然后依次调用next()获取值 - 迭代器的
next()方法返回{ value, done }格式的对象 - 普通对象默认不可迭代,需要手动实现
[Symbol.iterator]方法 - 实现迭代器后,对象也可以使用
for...of循环
目录