Skip to content

迭代协议(Iteration protocols) #196

Open
@yaofly2012

Description

@yaofly2012

一、Iteration protocols

JS里可以通过for-in遍历对象,for遍历字符串和数组,并且数组还有独立的各种遍历方法。ES2015里又增加了一些数据集合(Set/Map/生成器函数)。为了对这些数据集合提供统一遍历方式引入了迭代协议。

迭代协议由两部分构成:

  1. 可迭代协议(iterable protocol)
  2. 迭代器协议(iterator protocol)

二、可迭代协议(iterable protocol) & 可迭代对象

2.1 可迭代协议(iterable protocol)

The iterable protocol allows JavaScript objects to define or customize their iteration behavior。

协议内容:

  1. 对象本身(或者原型链上)具有Symbol.iterator成员方法;
  2. Symbol.iterator成员方法返回值是个迭代器

通过名字也能看出Symbol.iterator成员方法就是为了获取可迭代对象的迭代器的。

2.2 可迭代对象

实现了可迭代协议的对象叫可迭代对象

2.3 可迭代对象的语法支持

1. for-of遍历

for (let value of ['a', 'b', 'c']) {
    console.log(value);
}

2. 展开语法...

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

3. yield*遍历

var gen = function* () {
    yield 1;
    yield* [12, 123];
    return 3;
}

4. 解构赋值

var gen = function* () {
    yield 1;
    yield* [12, 123];
    return 3;
}

var g = gen();
var [a, b, c] = g;

console.log(a, b, c); // 1 12 123

三、迭代器协议(iterator protocol)& 迭代器(iterator )

迭代器协议定义如何产生一系列值的标准方式(就像Promise/A+规范定义Promise对象)。
实现迭代器协议的对象叫迭代器

3.1 协议内容

  1. 具有next成员方法;
  2. next成员方法返回非null的对象,并且对象至少具有两个属性:
  • value: 迭代器一系列值的具体一个值,done=true时表示没有值了
    此时忽略value的值,这里经常误以为是最后一个值。上面列举的可迭代最新的遍历语法都会忽略done=truevalue.
  • done: 标记是否还具有下个值。

这样就可以获取迭代器一系列的值以及判断是否还具有更多的值。

3.2 可迭代协议(iterable protocol)和迭代器协议(iterator protocol)对比

两者是不同的:

  1. 前者定义如何遍历一个对象;
  2. 后者定义如何产生遍历的一系列值。

一个对象可能既是可迭代对象,也可能是迭代器。

四、实战

4.2 内置可迭代对象

  1. String
  2. Array, TypedArray,
  3. Set,
  4. Map
  5. 生成器generator对象
  6. arguments对象

内置可迭代对象返回的迭代器也是个可迭代对象

内置可迭代对象返回的迭代器也是个可迭代对象(额,有点绕~)并且两者的迭代器是相等的

const arr = [ 1, 2, 3 ]
const iter = arr[Symbol.iterator]()
for (const item of iter) {
    console.log(item) // 1 2 3
}
const iter2 = iter[Symbol.iterator]()
console.log(iter === iter2) // true
const iter3 = iter[Symbol.iterator]()[Symbol.iterator]()[Symbol.iterator]()
console.log(iter === iter3) // true

4.3 自定义可迭代对象

var iterableName = {
    [Symbol.iterator]: () => {
        var index = 0;
        var val = ['john', 'lucy']

        return {
            next: () => {
                return val.length === index ? {
                    done: true
                } : {
                    value: val[index++],
                    done: false
                }
            }
        }
    }
}

for(var a of iterableName) {
    console.log(a)    
}

// ['john', 'lucy']
[...iterable] 

代码输出判断:

var a = {
  [Symbol.iterator]: () => {
    var index = 0;
    return {
      next: () => {
        if(index === 3) {
          return {
            done: true,
            value: 9
          }
        }

        return {
          done: false,
          value: ++index
        }
      }
    }
  }
}

for(let v of a) {
  console.log(v)
}

参考

  1. MDN Iteration protocols

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions