ES6之可迭代协议与for-of循环

115 阅读2分钟

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 。将每一项放到展开运算符的位置。这时,如果在展开运算符外面套上一个数组符号,就可以将对象转换为一个数组。