ES6之可迭代协议与for-of循环
我们之前不仅介绍了迭代器的概念,还声明了一个迭代器创建函数。实际上,ES6 规定了可迭代协议。它的意思是不管是对象,数组,伪数组,类数组还是任何类型,只要你满足它所规定的协议,就是一个可迭代对象。
协议内容为:可以在这个对象内找到一个知名符号属性:Symbol.iterator ,并且这个属性的属性值是一个迭代器创建函数。
const arr = [1, 2, 3, 4, 5]
const iterator = arr[Symbol.iterator]()
let result = iterator.next()
while (!result.done) {
const item = result.value
console.log(item)
result = iterator.next()
}
如果 arr 是一个数组,那么在它的原型上一定有 Symbol.iterator ,它是许多符号属性中的一个。我们可以直接调用它来得到一个迭代器,因为这个函数是迭代器创建函数。这个函数中一定有一个 next() 方法,我们可以通过循环不断地调用这个方法,每次都取出返回对象里面的 value ,直到返回对象里的 done 变为 true 。这就是 for-of 的原理。
const obj = {
a: 1,
b: 2,
[Symbol.iterator]() {
const keys = Object.keys(this)
let i = 0
return {
next: () => {
const propName = keys[i]
const propValue = this[propName]
const result = {
value: {
propName,
propValue
},
done: i >= keys.length
}
i++;
return result
}
}
}
}
for (const item of obj) {
console.log(item)
}
function test(a, b) {
console.log(a, b)
}
test(...obj)
可以看到,如果 obj 对象中没有这个知名符号属性,就无法使用 for-of 循环。for-of 循环里的 item 就是拿到迭代器,使用 next 不断调用,将返回对象里的 value 值赋值给 item 。
对于展开运算符,实际展开的就是可迭代对象。同样是从调用迭代器创建函数拿到迭代器,然后不断调用 next ,拿到里面的 value 。将每一项放到展开运算符的位置。这时,如果在展开运算符外面套上一个数组符号,就可以将对象转换为一个数组。