迭代协议

独自去流浪的博客 / 2024-08-30 / 原文

 

 

迭代协议

参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Iteration_protocols

 

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

 

迭代协议具体分为两个协议:可迭代协议和迭代器协议

 

可迭代协议

可迭代协议允许JavaScript对象定义或定制它们的迭代行为,例如,在一个for...of结构中,哪些值可以被遍历到。一些内置类型同时是内置可迭代对象,并且有默认的迭代行为,比如Array或者Map,而其他内置类型则不是(比如Object)。

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

属性
[Symbol.iterator] 返回一个符合迭代器协议的对象的无参数函数。

 

  

当一个对象需要被迭代的时候(比如被置入一个for...of循环时),首先,会不带参数调用它的@@iterator方法,然后使用此方法返回的迭代器要获得迭代的值。

值得注意的是调用此零个参数函数时,它将作为可迭代对象的方法进行调用。因此,在函数内部,this关键字可用于访问可迭代对象的属性,以决定在迭代过程中提供什么。

 

迭代器协议

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

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

属性
next

一个无参数函数,返回一个应当拥有以下两个属性的对象:

done(boolean)

如果迭代器可以产生序列中的下一个值,则为false。(这等价于没有指定done这个属性)

如果迭代器已将序列迭代完毕,则为true.这种情况下,value是可选的,

 

value

迭代器返回的任何JavaScript值,done为true时可省略

 

next()方法必须返回一个对象,该对象应当有两个属性:done和value,如果返回了一个非对象值(比如false或undefined),则会抛出一个TypeError异常("iterator.next() returned a non-object value")

 

 

 

 备注:不可能判断一个特定的对象是否实现了迭代器协议,然而,创造一个同时满足迭代器协议和可迭代协议的对象是很容易的

var myIterator = {
    next: function () {
        // ...
    },
    [Symbol.iterator]: function() { return this; };
}

使用迭代协议的例子

String是一个内置的可迭代对象

let someString = "Hi";
typeof someString[Symbol.iterator]; // "function"

String的默认迭代器会依次返回该字符串的各码点

let iterator = someString[Symbol.iterator]();
iterator + ""; // "[object String Iterator]"

iterator.next(); // { value: "h", done: false}
iterator.next(); // { value: "i", done: false}
iterator.next(); // { value: undefined, done: true}

一些内置的语法结构——比如展开语法——其内部实现也使用了同样的迭代协议:

[...someString] // ["h", "i"]

我们可以通过提供自己的@@iterator方法,重新定义迭代行为: