10
2020
01

ES6生成器 返回迭代器的函数

  生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。星号可以紧挨着function关键字,也可以在中间添加一个空格

// 生成器

function *createIterator() {

    yield 1;

    yield 2;

    yield 3;

}

// 生成器能像正规函数那样被调用,但会返回一个迭代器

let iterator = createIterator();

console.log(iterator.next().value); // 1

console.log(iterator.next().value); // 2

console.log(iterator.next().value); // 3

  在这个示例中,createlterator()前的星号表明它是一个生成器;yield关键字也是ES6的新特性,可以通过它来指定调用迭代器的next()方法时的返回值及返回顺序。生成迭代器后,连续3次调用它的next()方法返回3个不同的值,分别是1、2和3。生成器的调用过程与其他函数一样,最终返回的是创建好的迭代器

  生成器函数最有趣的部分是,每当执行完一条yield语句后函数就会自动停止执行。举个例子,在上面这段代码中,执行完语句yield 1之后,函数便不再执行其他任何语句,直到再次调用迭代器的next()方法才会继续执行yield 2语句。生成器函数的这种中止函数执行的能力有很多有趣的应用

  使用yield关键字可以返回任何值或表达式,所以可以通过生成器函数批量地给迭代器添加元素。例如,可以在循环中使用yield关键字

function *createIterator(items) {

    for (let i = 0; i < items.length; i++) {

        yield items[i];

    }

}

let iterator = createIterator([1, 2, 3]);

console.log(iterator.next()); // "{ value: 1, done: false }"

console.log(iterator.next()); // "{ value: 2, done: false }"

console.log(iterator.next()); // "{ value: 3, done: false }"

console.log(iterator.next()); // "{ value: undefined, done: true }"

// 之后的所有调用

console.log(iterator.next()); // "{ value: undefined, done: true }"

  在此示例中,给生成器函数createlterator()传入一个items数组,而在函数内部,for循环不断从数组中生成新的元素放入迭代器中,每遇到一个yield语句循环都会停止;每次调用迭代器的next()方法,循环会继续运行并执行下一条yield语句

  生成器函数是ES6中的一个重要特性,可以将其用于所有支持函数使用的地方

使用限制

  yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误

function *createIterator(items) {

    items.forEach(function(item) {

        // 语法错误

        yield item + 1;

    });

}

  从字面上看,yield关键字确实在createlterator()函数内部,但是它与return关键字一样,二者都不能穿透函数边界。嵌套函数中的return语句不能用作外部函数的返回语句,而此处嵌套函数中的yield语句会导致程序抛出语法错误

生成器函数表达式

  也可以通过函数表达式来创建生成器,只需在function关键字和小括号中间添加一个星号(*)即可

let createIterator = function *(items) {

    for (let i = 0; i < items.length; i++) {

        yield items[i];

    }

};

let iterator = createIterator([1, 2, 3]);

console.log(iterator.next()); // "{ value: 1, done: false }"

console.log(iterator.next()); // "{ value: 2, done: false }"

console.log(iterator.next()); // "{ value: 3, done: false }"

console.log(iterator.next()); // "{ value: undefined, done: true }"

// 之后的所有调用

console.log(iterator.next()); // "{ value: undefined, done: true }"

  在这段代码中,createlterator()是一个生成器函数表达式,而不是一个函数声明。由于函数表达式是匿名的,因此星号直接放在function关键字和小括号之间。此外,这个示例基本与前例相同,使用的也是for循环

  [注意]不能用箭头函数来创建生成器

生成器对象的方法

  由于生成器本身就是函数,因而可以将它们添加到对象中。例如,在ES5风格的对象字面量中,可以通过函数表达式来创建生成器

var o = {

    createIterator: function *(items) {

            for (let i = 0; i < items.length; i++) {

                yield items[i];

            }

        }

};

let iterator = o.createIterator([1, 2, 3]);

  也可以用ES6的函数方法的简写方式来创建生成器,只需在函数名前添加一个星号(*)

var o = {

    *createIterator(items) {

            for (let i = 0; i < items.length; i++) {

                yield items[i];

            }

        }

};

let iterator = o.createIterator([1, 2, 3]);

  这些示例使用了不同于之前的语法,但它们的功能实际上是等价的。在简写版本中,由于不使用function关键字来定义createlterator()方法,因此尽管可以在星号和方法名之间留白,但还是将星号紧贴在方法名之前

状态机

  生成器的一个常用功能是生成状态机

let state = function*(){

    while(1){

        yield 'A';

        yield 'B';

        yield 'C';

    }

}

let status = state();

console.log(status.next().value);//'A'

console.log(status.next().value);//'B'

console.log(status.next().value);//'C'

console.log(status.next().value);//'A'

console.log(status.next().value);//'B'

原文链接:https://www.qiquanji.com/post/7841.html

本站声明:网站内容来源于网络,如有侵权,请联系我们,我们将及时处理。

gzh

微信扫码关注

更新实时通知

« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。