/**
* Generator
* 生成器对象是由一个 generator function 返回的,
* 并且它符合可迭代协议和迭代器协议。
* 迭代协议具体分为两个协议:可迭代协议和迭代器协议。
* 可迭代协议
* 允许 JavaScript 对象定义或定制它们的迭代行为,
* 例如,在一个 for..of 结构中,哪些值可以被遍历到。
* 一些内置类型同时是内置可迭代对象,并且有默认的迭代行为,
* 比如 Array 或者 Map,而其他内置类型则不是(比如 Object))。
* 要成为可迭代对象, 一个对象必须实现 @@iterator 方法。
* 这意味着对象(或者它原型链上的某个对象)必须有一个键为 @@iterator 的属性,
* 可通过常量 Symbol.iterator 访问该属性:
* [Symbol.iterator] 一个无参数的函数,其返回值为一个符合迭代器协议的对象。
* 迭代器协议定义了产生一系列值(无论是有限个还是无限个)的标准方式。
* 当值为有限个时,所有的值都被迭代完毕后,则会返回一个默认返回值。
* 只有实现了一个拥有以下语义(semantic)的 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")。
*/
const isGeneratorObject = (target) => {
if (typeof target !== 'object' || target === null) {
// throw TypeError(`${target} is not object`);
return false;
}
const ger = target[Symbol.iterator];
return typeof ger === 'function';
};
const typeArr = [123, '123', undefined, true, null, Symbol('test'), [], {}, new Map(), new Set()];
// for (let item of typeArr) {
// console.log(isGeneratorObject(item));
// };
const ger1 = [][Symbol.iterator]();
// console.log(ger1);
/**
* Generator.prototype.next()
* next() 方法返回一个包含属性 done 和 value 的对象。
* 该方法也可以通过接受一个参数用以向生成器传值。
* value
* 向生成器传递的值.
* 返回的对象包含两个属性:
* done (布尔类型)
* 如果迭代器超过迭代序列的末尾,则值为 true。
* 在这种情况下,value可选地指定迭代器的返回值。
* 如果迭代器能够生成序列中的下一个值,则值为false。 这相当于没有完全指定done属性。
* value - 迭代器返回的任意的Javascript值。当 done 的值为 true 时可以忽略该值。
* =>{value:any,done:boolen}
*/
//gen.next(value)
const ger2 = new Map([['name', 'ger2'], ['age', 2]])[Symbol.iterator]();
const target = ger2.next(4);
// console.log(target, ger2.next(), ger2.next(8));
const ger3 = function* () {
yield 1;
yield 2;
yield 3;
};
// console.log(ger3().next());
const ger4 = function* () {
let index = 0;
while (index < 10) {
const val = yield null;
console.log(val, index);
index += Number.isInteger(val) ? val : 1;
}
};
const target4 = ger4();
// console.log(target4.next(), target4.next(8),target4.next(3));
// 请注意,第一次调用没有记录任何内容,因为生成器最初没有产生任何结果。
/**
* Generator.prototype.return()
* return() 方法返回给定的值并结束生成器。
* 如果对已经处于“完成”状态的生成器调用return(value),则生成器将保持在“完成”状态。
* 如果没有提供参数,则返回对象的value属性与示例最后的.next()方法相同。
* 如果提供了参数,则参数将被设置为返回对象的value属性的值。
* => {value:doneValue / returnValue:done:true}
*/
//gen.return(value)
const ger5 = function* () {
let index = 0;
while (index < 5) {
yield index++;
}
};
const target5 = ger5();
// console.log(target5.next(),target5.return(6),target5.next(9));
/**
* Generator.prototype.throw()
* throw() 方法用来向生成器抛出异常,并恢复生成器的执行,返回带有 done 及 value 两个属性的对象。
* exception
* 用于抛出的异常。 使用 Error 的实例对调试非常有帮助.
* 返回带有两个属性的对象:
* done (boolean)
* 如果迭代器已经返回了迭代序列的末尾,则值为 true。在这种情况下,可以指定迭代器 value 的返回值。
* 如果迭代能够继续生产在序列中的下一个值,则值为 false。 这相当与不指定 done 属性的值。
* value - 迭代器返回的任何 JavaScript 值。当 done 是 true 的时候可以省略。
* => {done:true}
*/
//gen.throw(exception)
const ger6 = function* () {
let index = 0;
try {
while (index < 5) {
yield index++;
}
} catch (e) {
console.log('enter', e);
}
};
const target6 = ger6();
// console.log(target6.next(), target6.throw(new Error('yes')));
console