迭代协议
可迭代协议
可迭代协议允许 JavaScript 对象定义或定制它们的迭代行为
对象实现了**@@iterator**
方法可以成为可迭代对象,可通过常量Symbol.iterator
作为键值访问该方法。该方法返回一个 符合迭代器协议的对象。
该方法函数可以是普通函数,也可以是生成器函数,以便在调用时返回迭代器对象。 在此生成器函数的内部,可以使用yield
提供每个条目。
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
迭代器协议
迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。
对象拥有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 }
}
生成器对象(Generator Object)与生成器函数(Generator Function)
function*()
这种声明方式会定义一个生成器函数,函数会返回一个生成器对象。生成器对象同时实现了可迭代协议和迭代器协议。所以说,生成器对象既是一个可迭代对象,也是一个迭代器。
调用生成器函数不会执行函数内部的语句,而是返回一个生成器对象。由于生成器对象实现了迭代器协议,所以对象中有next()
函数。当next()
方法被首次(后续)调用时,生成器函数内的语句会执行到第一个(后续)出现的yield
的位置为止。next()
方法返回的对象里面有两个属性 value
和 done
。value
属性的值是本次yield
表达式的值。
function myGeneratorFunction*() {
yield A OP B
}
const myGeneratorObject = myGeneratorFunction();
console.log(myGeneratorObject.next().value); // 这里value的值就是 yield 后面表达式 A OP B 的值
笔者注: 这里插播一条经常看到的面试题 为什么生成器对象第一次next方法返回值的value是0呢?看一下上面的定义 “value属性的值是本次yield表达式的值。” 所以这里需要结合另外一个知识点来解答: i++ 与 ++i的区别。
- i++ 表达式的值是i的值。
- ++i 表达式的值是 i+1 的值。
所以生成器对象第一次next方法返回值的value 是 index++ 表达式的值,也就是index的值,第一次的时候index的值是0。
function myGeneratorFunction*() {
let index = 0;
while (true) {
yield index ++;
}
}
const myGeneratorObject = myGeneratorFunction();
console.log(myGeneratorObject.next().value); // 0
console.log(myGeneratorObject.next().value); // 1
在调用next()
方法时,如果传入了参数,参数会赋值给上一条执行的yield
语句的左边变量。
function *gen(){
yield 10;
x=yield 'foo';
yield x;
}
var gen_obj=gen();
console.log(gen_obj.next());// 执行 yield 10,返回 10
console.log(gen_obj.next());// 执行 yield 'foo',返回 'foo'
console.log(gen_obj.next(100));// 将 100 赋给上一条 yield 'foo' 的左值,即执行 x=100,返回 100
console.log(gen_obj.next());// 执行完毕,value 为 undefined,done 为 true
当在生成器函数中显式 return
时,会导致生成器立即变为完成状态,即调用 next()
方法返回的对象的 done
为 true
。如果 return
后面跟了一个值,那么这个值会作为当前调用 next()
方法返回的 value
值。