对象解构赋值的实现方式
通过实现迭代器协议让对象支持数组解构赋值
问题
如何让 var [a, b] = {a: 1, b: 2} 解构赋值成功?
解答
问题分析
直接对对象使用数组解构会报错:
const obj = {
a: '1',
b: '2',
}
const [a, b] = obj
// TypeError: obj is not iterable
错误提示对象不可迭代。要解决这个问题,需要让对象实现迭代器协议。
迭代器协议
根据 MDN 定义,要成为可迭代对象,必须实现 @@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 }
数组解构的本质
数组解构实际上是调用迭代器:
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: obj[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()方法,返回{ value, done }格式 - 实现后对象也可以使用
for...of遍历 next()方法通过done标识是否迭代完成
目录