• 24小时服务热线:400-088-1128

当前位置 南顺网络>> 知识拓展

js生成器

使用生成器函数

生成器函数几乎是一个完全崭新的函数类型,它和标准的普通函数完全不同。生成器函数能够生成一组值的序列。但是每个值的生成是基于每次请求,并不同于标准函数那样立即生成。生成器几乎从不挂起,随后当对另一个值的请求到来后,生成器就会从上次离开的位置恢复执行。

function assert(condition, text) {

    if(condition) {

        console.log(text);

    }

}

function* WeaponGenerator() {

    yield "Katana";

    yield "Wakizashi";

    yield "Kusarigama";

}

for (let weapon of WeaponGenerator()) {

    assert(weapon !== undefined, weapon);

}

创建生成器是在function后面加上一个星号(*),这样一来生成器函数体内就能使用新关键词yield,从而生成独立的值

通过迭代器对象控制生成器

function assert(condition, text) {

    if(condition) {

        console.log(text);

    }

}

function* WeaponGenerator() {

    yield "Katana";

    yield "Wakizashi";

}

// 得到一个迭代器

const weaponsIterator = WeaponGenerator();

//调用迭代器的next方法生成器请求一个新的值

const result1 = weaponsIterator.next();

assert(typeof result1 === "object" && result1.value === "Katana" && !result1.done, "Katana received");

const result2 = weaponsIterator.next();

assert(typeof result2 === "object" && result2.value === "Wakizashi" && !result2.done, "Wakizashi received");

const result3 = weaponsIterator.next();

assert(typeof result3 === "object" && result3.value === undefined && result3.done, "There are no more results!");

迭代器用于控制生成器的执行,迭代器对象暴露的最基本接口是next方法。这个方法可以用来向生成器请求一个值,从而控制生成器。

我们可以使用yield操作符将执行权交给另外一个生成器

function assert(condition , text) {

    if (condition) {

        console.log(text);

    }

}

function * WarriorGenerator() {

    yield "Sun Tzu";

    yield * NinjaGenerator();

    yield "Genghis Khan";

}

function * NinjaGenerator(){

    yield "Hattori";

    yield "Yoshi";

}

for (let warrior of WarriorGenerator()) {

    assert(warrior !== null, warrior);

}

在上述的程序中,迭代器使用yield * 操作符,程序会跳转到另外一个生成器上执行。


用生成器生成ID序列

function assert(condition , text) {

    if (condition) {

        console.log(text);

    }

}

function * IdGenerator() {

    let id = 0;

    while (true) {

        yield ++id;

    }

}

//生成迭代器对象

const idIterator = IdGenerator();

const ninja1 = {id: idIterator.next().value};

const ninja2 = {id: idIterator.next().value};

const ninja3 = {id: idIterator.next().value};

assert(ninja1.id === 1, "1");

assert(ninja2.id === 2, "2");

assert(ninja3.id === 3, "3");

迭代器中包含一个局部变量id,这个id仅能在生成器中访问,故而完全不必担心有人会不小心在代码的其他地方修改id值。

与生成器交互

我们能向生成器发送值,从而实现双向通信,使用生成器我们能够生成中间结果。

作为生成器函数参数发送值

function assert(condition , text) {

    if (condition) {

        console.log(text);

    }

}

function * NinjaGenerator(action) {

    const imposter = yield ("Hattori " + action);

    assert(imposter === "Hanzo", "The generator has been infilterated");

    yield ("Yoshi (" + imposter +") " + action);

}

const ninjaIterator = NinjaGenerator("skulk");

const result1 = ninjaIterator.next();

assert(result1.value === "Hattori skulk", "Hattori is skulking");

const result2 = ninjaIterator.next("Hanzo");

assert(result2.value === "Yoshi (Hanzo) skulk", "We have an imposter");

Hattori is skulking

The generator has been infilterated

We have an imposter

探索生成器内部构成

生成器的工作更像是一个小程序,一个状态中运动的状态机。

挂起开始:创建要给生成器后,最先以这种状态开始,其中的任何代码都没有执行。

执行:生成器中的代码执行的状态。执行要么是刚开始,要么是从上次挂起的时候继续的。

挂起过渡:当生成器的执行过程中遇到一个yield表达式,会创建一个包含着返回值的新对象,随后再挂起执行。

完成:如果执行到return语句或者全部代码执行完毕,生成器就进入该状态。

标准函数仅仅会被重复调用,每次调用都会创建一个新的执行环境上下文,相比之下,生成器执行的环境的上下文则会暂时挂起并再将来恢复。

————————————————

版权声明:本文为CSDN博主「绝尘花遗落」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/huayunhualuo/article/details/103661767