可迭代协议:规定对象是否可迭代-->对象属性上必须有一个Symbol.iterator属性,[Symbol.iterator] :一个无参数的函数(普通函数或者生成器函数),其返回值为一个符合迭代器协议的对象。
迭代器协议:规定了一个对象是否是迭代器:按照规定实现next(),具体查看MDN文档。
很多内置类型都实现了 Iterable 接口(也就是实现了可迭代协议)
原生语言特性其实接收可迭代对象(它们会先调用[Symbol.iterator]方法获取迭代器):
生成器函数(也就是*函数)产生生成器对象,生成器对象也实现了可迭代协议。
乍一看理解,仔细想没理解,然后自己让n=2,还原nTimes,等价于
function* nTimes() {
if (true) {
yield* (function* A() {
if (true) {
yield* (function* B() { })();
yield 0;
}
})();
yield 1;
}
}
最难理解的是n=0的时候
yield* (function* B() { })();
yield*后面必须跟一个可迭代对象,*号函数正好返回一个可迭代对象,但是当这个可迭代对象没有可以迭代的操作(也就是内部没有yield表达式)时候,会被忽略(yield* (function* B() { })(); 被当成一个同步代码在执行),所以应该执行yield 0;
let aa = nTimes();
console.log(aa.next());
console.log(aa.next());
所以第一次打印出{ value: 0, done: false }。
也就是
(function* A() {
if (true) {
yield* (function* B() { })();
yield 0;
}
})()
执行完毕。
所以第二次执行的时候就相当于在执行yield 1;,所以打印出来就是{ value: 1, done: false }。
所以yield* nTimes(3 - 1) 等价于
yield* [yield 2 - 1, yield 1 - 1];
nTimes(3) 等价于nTimes3()
function* nTimes(n) {
if (n > 0) {
yield* nTimes(n - 1);
yield n - 1;
}
}
function* nTimes3() {
yield* [yield 2 - 1, yield 1 - 1];
yield 3 - 1;
}
//TODO持续更新