ES6 迭代协定

迭代协定

可迭代协定(The iterable protocol) 和 迭代器协定(The iterator protocol)是对 ECMAScript 2015 的补充,不是新的内置或语法,仅仅是协定。能够被任何遵照某些商定的对象来完成。

可迭代协定

可迭代协定许可 JavaScript 对象去定义或许定制它们的迭代行动。

一些内置范例是可迭代,比方 Array,TypeArray,Map,Set,String,在 for…of 构造中能够轮回遍历值,而 Object 就不是。

为了变成可迭代对象,一个对象必需完成 @@iterator 要领, 意义是这个对象(或许它原型链 prototype chain 上的某个对象)必需有一个名字是 Symbol.iterator 的属性:

PropertyValue
[Symbol.iterator]无参函数,该函数返回一个对象,该对象相符迭代器协定

迭代器协定

迭代器协定定义了一种规范的体式格局来发生有限或无穷序列的值

当一个对象完成了 next() 要领,而且相符以下定义,则该对象就是一个迭代器对象。

属性
next一个无参函数,返回一个对象,该对象具有两个属性 done 和 value

done(boolean)

  • 假如迭代器已到了迭代序列的末端,done 为 false
  • 假如迭代器还能够发生序列下一个值,done 为 true

value

迭代器返回的任何 JavaScript 值,当 done 为 true,可疏忽。

next 要领必需是返回包括 done 和 value 属性的对象,假如非对象(类如 false, undefined)返回,将会抛出 TypeError

例子

可迭代协定例子

自定义一个可迭代对象
const iterableObj = {}
iterableObj[Symbol.iterator] = function* () {
    yield 1
    yield 2
    yield 3
}
console.log([...iterableObj])
接收可迭代对象的内置 APIs

很多 APIs 接收可迭代对象作为参数,比方 Map([iterable]),WeakMap([iterable]),Set([iterable]),WeakSet([iterable])

const myObj = {}
new Map([[1, 'a'], [2, 'b'], [3, 'c']]).get(2)               // "b"
new WeakMap([[{}, 'a'], [myObj, 'b'], [{}, 'c']]).get(myObj) // "b"
new Set([1, 2, 3]).has(3)                                    // true
new Set('123').has('2')                                      // true
new WeakSet(function* () {
    yield {}
    yield myObj
    yield {}
}()).has(myObj)                                              // true
用于可迭代对象的语法

一些语句或许表达式可用于可迭代对象,比方 for…of 轮回,spread operator,yield*,destructuring assignment。

// for...of
for (let i of [1, 2, 4]) {
    console.log(i)
    // 1
    // 2
    // 4
}

// spread operator
console.log([...'abc']) // ["a", "b", "c"]

// yield*
function* gen() {
    yield* ['a', 'b', 'c']
}
console.log(gen().next()) // {value: "a", done: false}

// destructuring assignment
[a, b] = new Set(['a', 'b'])
console.log(a) // a

迭代器协定例子

简朴迭代器
function makeIterator(array) {
    let nextIndex = 0
    return {
        next() {
            return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { done: true }
        }
    }
}

const it = makeIterator(['a', 'b'])

console.log(it.next()) // {value: "a", done: false}
console.log(it.next()) // {value: "a", done: false}
console.log(it.next()) // {done: true}
生成器
function* makeSimpleGenerator(arr) {
    let nextIndex = 0
    while (nextIndex < array.length) {
        yield array[nextIndex++]
    }
}

const it = makeSimpleGenerator(['a', 'b'])

console.log(it.next()) // {value: "a", done: false}
console.log(it.next()) // {value: "a", done: false}
console.log(it.next()) // {value: undefined, done: true}
ES6 class
class SimpleIterator {
    constructor(data) {
        this.data = data
        this.index = 0
    }

    [Symbol.iterator]() {
        return {
            next: () => {
                return this.index < this.data.length ? { value: this.data[this.index++], done: false } : { done: true }
            }
        }
    }
}

const simple = new SimpleIterator([1, 3, 9])

for (let i of simple){
    console.log(i) // 1 3 9
}

再谈生成器 generator

从上面的示例能够看出,generator 是比较特别的,generator 既是一个 生成器对象,又是一个 可迭代对象!

const generatorObj = function* () {
    yield 1
    yield 2
    yield 3
}()

console.log(typeof generatorObj.next) // function

console.log(typeof generatorObj[Symbol.iterator]) // function

console.log(generatorObj[Symbol.iterator]() === generatorObj) // true

文章如有马虎,迎接人人发问交换!

参考

  1. MDN: Iteration protocols
    原文作者:山顶的男人
    原文地址: https://segmentfault.com/a/1190000013120525
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞