ES6之迭代协议

209 阅读2分钟

前言

作为 ECMAScript 2015 的一组补充规范,迭代协议并不是新的内置实现或语法,而是协议。这些协议可以被任何遵循某些约定的对象来实现。

es6的迭代协议分两种可迭代协议和迭代器协议

可迭代协议

可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为。

javascript内置的可迭代数据类型

  • String
  • Map
  • Array
  • Set
  • TypedArray

Object不是可迭代协议,要成为可迭代对象, 一个对象必须实现  @@iterator 方法。这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,可通过常量 [Symbol.iterator] 访问该属性

迭代器协议

迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。

只有实现了一个拥有以下语义的 next()  方法,一个对象才能成为迭代器:

  1. 返回一个对象必须有next()方法
  2. next()方法返回一个对象,有value属性和done属性
  3. done属性为Boolean,这个属性在于这个迭代是否结束,如果没有返回done属性等价于 done: false
  4. value 可以为任何类型(当done为true的时候可以省略)

实现一个迭代器协议

根据上面的要求可以给Object添加一个可迭代协议并使用for...of...来遍历Object
测试输出结果环境为node v16.15.0

使用常规方式实现

Object.prototype[Symbol.iterator] = function () {
  const list = Object.entries(this);
  let index = 0;
  return {
    next() {
      if (index < list.length) {
        return {
          done: false,
          value: list[index++][1],
        };
      } else {
        return {
          done: true,
        };
      }
    },
  };
};

// 测试
const a = {a:1,b:2,c:3,d:4,e:5,f:6}

for(const value of a) {
console.log(value)
}

// 输出
// 1
// 2
// 3
// 4
// 5
// 6

使用生成器(Generator)改写

Object.prototype[Symbol.iterator] = function* () {
  yield* Object.values(this);
};

// 测试
const a = {a:1,b:2,c:3,d:4,e:5,f:6}

for(const value of a) {
console.log(value)
}

// 输出
// 1
// 2
// 3
// 4
// 5
// 6

可接受可迭代对象API

  • new Map([iterator])
  • new Set([iterator])
  • new WeakSet([iterator])
  • new WeakMap([iterator])
  • Promise.all([iterator])
  • Promise.race([iterator])
  • Array.from([iterator])

需要可迭代协议的语法

  • for...of...
  • ...
  • yield*
  • 解构赋值

结尾

本文参考: developer.mozilla.org/zh-CN/docs/…