Generator函数

//Generator的简单语法
console.log("=========Generator的简单语法============")
//yield定义的表达式,只有next()函数才能执行直接调用 function* 的函数无法执行
function* helloWorldGenerator() {// 使用   function* 关键字定义Generator函数
    yield 'hello';               // 使用yield关键字 定义不同的内部状态
    yield 'world';
    return 'end';                // 停止该状态
}

var hw = helloWorldGenerator();
console.log(hw.next());

console.log(hw.next());
console.log(hw.next());
console.log(hw.next());
/*
{ value: 'hello', done: false }
{ value: 'world', done: false }
{ value: 'end', done: true }
{ value: undefined, done: true }
*/

//Generator的应用==》遍历一维+二维数组
console.log("=========Generator的应用==》遍历一维+二维数组============")
let arrYield = [1, [[2, 3], 4], [5, 6]];
let flat = function* (arr) {
    let length = arr.length;
    for (let i = 0; i < length; i++) {
        let item = arr[i];
        if (typeof item !== 'number') {
            yield* flat(item);
        } else {
            yield item;
        }
    }
}

for (let f of flat(arrYield)) {
    console.log(f);//1,2,3,4,5,6
}

//简单的Iterator函数生成方式
console.log("=========简单的Iterator函数生成方式============")
let myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
    yield 4;
}

console.log([...myIterable]);//[1,2,3,4]

//Generator函数与Iterator接口的关系
console.log("=========Generator函数与Iterator接口的关系============")
function* gen() {}

let g = gen();
console.log(g[Symbol.iterator]() == g); //true

//next(true)返回上一个yield表达式的返回值
console.log("=========next(true)返回上一个yield表达式的返回值============")
function* previousYieldValue() {
    for (let i = 0; true; i++) {
        let reset = yield i;//reset 为next()函数传入的值
        console.log("reset",reset);
        if(reset) {i = i-2};
    }
}

let previousValue = previousYieldValue();
 console.log(previousValue.next());
 console.log(previousValue.next());
 console.log(previousValue.next());
 console.log(previousValue.next(true));
 console.log(previousValue.next());
/*
    { value: 0, done: false }
    reset undefined
    { value: 1, done: false }
    reset undefined
    { value: 2, done: false }
    reset true
    { value: 1, done: false }
    reset undefined
    { value: 2, done: false }
*/

//  next()函数是用于向generator函数进行状态变化时的过程中
//  next()方法的参数表示上一个yield表达式的返回值,所以第一次使用next方法时,传递参数是无效的
//  yeild定义的表达式将在next()函数调用时,将结果返回给next()函数,但不会再generator中执行
console.log("=========next()函数是用于向generator函数进行状态变化时的过程中    改变yield表达式内部值得一种方式============");
function* nextFoo(x) {
    let y = 2 * (yield(x + 1));
    let z = yield (y / 3);
    return (x + y + z);
}

let nextFA = nextFoo(5);
console.log(nextFA.next());
console.log(nextFA.next());
console.log(nextFA.next());
/*
{ value: 6, done: false }
{ value: NaN, done: false }
{ value: NaN, done: true }
*/
let nextFB = nextFoo(5);
console.log(nextFB.next());
console.log(nextFB.next(12));//设置上一个yield(x+1)的值为12 所以y为24  ->当前返回z = 8
console.log(nextFB.next(13));//设置上一个yield的值为13即z=13     x+y+z = 5+24+13 = 42
/*
{ value: 6, done: false }
{ value: 8, done: false }
{ value: 42, done: true }
*/

//使用next方法向函数内部输入值得例子
function* dataConsumer() {
    console.log('Started');
    console.log(`1.${yield 222}`);
    console.log(`2.${yield}`);
}

let consumer = dataConsumer();
console.log(consumer.next());
console.log(consumer.next('a'));
console.log(consumer.next('b'));
/*
Started
{ value: 222, done: false }
1.a
{ value: undefined, done: false }
2.b
{ value: undefined, done: true }
*/
//要想第一个next()就可以传值的写法
function wrapper(generatorFunction) {
    return function (...args) {
        let generatorObject = generatorFunction(...args);
        generatorObject.next();
        return generatorObject;
    };
}
const wrapped = wrapper(function* () {
    console.log(`First input: ${yield}`);
    return 'DONE';
})

console.log(wrapped().next('hello~'));
/*
First input: hello~
{ value: 'DONE', done: true }

*/

console.log("===========for...of循环自动遍历Generator函数,不需要使用next方法=============")
//for...of循环自动遍历Generator函数,不需要使用next方法
function* forOf() {
    yield 1;
    yield 2;
    return 3;
}

for (let v of forOf()) {
    console.log(v);//1,2
}

/*
    只显示了2个yield表达式的值,一旦next方法返回对象done属性为true,for...of循环就会终止,且不会返回该对象,所以return不包括在for...of循环中
*/

//使Object能使用for...of进行遍历
console.log('=====================使Object能使用for...of进行遍历========================');
function* objectEntries(obj) {
    let propKeys = Reflect.ownKeys(obj);

    for (let propKey of propKeys) {
        yield [propKey, obj[propKey]];
    }

}
let jane = {first:'Jane', last: 'Doe'}

for (let [key, value] of objectEntries(jane)) {
    console.log(`${key}:${value}`);/*first:Jane last:Doe*/
}

//Generator.prototype.throw()方法
console.log("==========Generator.prototype.throw()方法==================")
let throwFunction = function* () {
    try {
        yield 1;
    }catch (e) {
        console.log('内部捕获',e)
    }
    yield 2;
};

let i = throwFunction();
i.next();

try {
    console.log(i.throw('a'));//执行generator的catch方法后    自动执行下一个yield
    i.throw('b');//因为generator的catch方法已经执行过了,所以抛出异常
} catch (e) {
    console.log("外部捕捉",e);
}

/*
    内部捕获 a
    外部捕捉 b
*/

let i2 = throwFunction();
try {
    console.log(i2.throw('c'));//执行generator的catch方法后    自动执行下一个yield
}catch (e) {
    console.log("外部捕获", e);//外部捕获 c,因为未执行next方法,仍未到Generator函数内部
}
let i3 = throwFunction();
console.log(i3.next());
console.log(i3.next());

try{
    console.log(i3.throw('D'))//执行generator的catch方法后    自动执行下一个yield
}catch (e) {
    console.log('外部捕获', e);//外部捕获 D     因为第2个next外部没有try...catch语句
}
/*

内部捕获 a
{ value: 2, done: false }
外部捕捉 b
外部捕获 c
{ value: 1, done: false }
{ value: 2, done: false }
外部捕获 D

*/

//Generator.prototype.return()  终结遍历Generator函数
function* returnFunction() {
    yield 1;
    yield 2;
    yield 3;
}

let returnFun = returnFunction();
console.log(returnFun.next());
console.log(returnFun.return('foo'));
console.log(g.next());


//如果Generator函数内部哟try...finally代码块,且正在执行try代码块,那么return方法会推迟到finally代码块执行完在执行
function* numbers() {
    yield 1;
    try {
        yield 2;
        yield 3;
    }finally {
        yield 4;
        yield 5;
    }
    yield 6;
}

let numb = numbers();
console.log(numb.next());
console.log(numb.next());
console.log(numb.return(7));
console.log(numb.next());
console.log(numb.next());

/*
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 4, done: false }
{ value: 5, done: false }
{ value: 7, done: true }
*/

//yield* 表达式    如果在Generator函数内部,调用另一个Generator函数,需要在前者的函数体内部,自己手动完成遍历
console.log("================yield* 表达式===================")
function* iteratorFunction() {
    yield 'a';
    yield 'b';
}

function* barFunction() {
    yield 'x';
    for (let i of iteratorFunction()) {
        console.log(i);//a,b
    }
    yield 'y';
}

for (let v of barFunction()) {
    console.log(v);//x,a,b,y
}

let stringsBarFunction = barFunction();
console.log(stringsBarFunction.next());
console.log(stringsBarFunction.next());
console.log(stringsBarFunction.next());
console.log(stringsBarFunction.next());
/*
{ value: 'x', done: false }
a
b
{ value: 'y', done: false }
{ value: undefined, done: true }
{ value: undefined, done: true }
*/

//使用    yield*  只要有Iterator接口就能实现遍历
function* yieldFunction() {
    yield 'x';
    yield* iteratorFunction();
    yield 'y';
}
//等同于
function* yieldBarFunction() {
    yield 'x';
    yield 'a';
    yield 'b';
    yield 'y';
}
//等同于
function* yieldBarForFunction() {
    yield 'x';
    for (let v of yieldFunction()) {
        yield v;
    }
    yield 'y';
}
for (let v of yieldFunction()) {
    console.log('yieldFunction', v);//x,a,b,y
}
let yieldFunction1 = yieldFunction();
console.log(yieldFunction1.next());
console.log(yieldFunction1.next());
console.log(yieldFunction1.next());
console.log(yieldFunction1.next());
/*
{ value: 'x', done: false }
{ value: 'a', done: false }
{ value: 'b', done: false }
{ value: 'y', done: false }
*/

//另一个例子
function* inner() {
    yield 'hello!';
    yield 'hello1!';

}

function* outer1() {
    yield 'open';
    yield inner();
    yield 'close';
}

let genOuter = outer1();
console.log(genOuter.next().value);//open
console.log(genOuter.next().value);//Object [Generator] {}
console.log(genOuter.next().value);//close
function* outer2() {
    yield 'open';
    yield* inner();
    yield 'close';
}

let genOuter2 = outer2();
console.log(genOuter2.next().value);//open
console.log(genOuter2.next().value);//hello!
console.log(genOuter2.next().value);//hello1!
console.log(genOuter2.next().value);//close


//如果被代理的Generator函数有return语句,那么久可以向代理它的Generator函数返回数据
function* fooReturn() {
    yield 2;
    yield 3;
    return 'fooReturn';
}

function* barFunctionReturn() {
    yield 1;
    let v = yield* fooReturn();
    console.log('v: ' + v);
    yield 4;
}

let it = barFunctionReturn();
console.log(it.next());//{ value: 1, done: false }
console.log(it.next());//{ value: 2, done: false }
console.log(it.next());//{ value: 3, done: false }
                       //v: fooReturn
console.log(it.next());//{ value: 4, done: false }
console.log(it.next());//{ value: undefined, done: true }

//作为对象属性的Generator函数简写成以下形式
let objGenerator = {
    * myGeneratorMetod() {

    },
    myGeneratorMetod2:function* () {

    }
}

//9.generator函数的this
//10.generator函数的含义
//11.Generator与上下文
//12应用
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容