前言

  生成器gengrator是es6 新增的函数功能,它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 本文来总结一下JavaScript 中生成器的相关知识点。

正文

  1、 生成器是什么

  生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。 生成器函数使用 function* 语法编写。 最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。 通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。

  2、 生成器实例( 通过yield 中断执行)

  (1)普通生成器函数

  调用生成器函数会产生一个类似于迭代器的生成器对象,。生成器对象一开始处于暂停执行(suspended)的状态。与迭代器相似,生成器对象也实现了 Iterator 接口,它们默认的迭代器是自引用的,因此具有 next() 方法。调用这个方法会让生成器开始执行,遇到yield关键字函数暂停,再次调用next()继续执行函数,yield并不回像return 一样立即结束函数,只是暂停这个生成器函数。

  注意:箭头函数不能用来定义生成器函数

        function* createIterator() {
yield 1;
yield 2;
yield 3;
}
console.log(createIterator());// createIterator {<suspended>}
console.log(createIterator()[Symbol.iterator]());// createIterator {<suspended>},因此可以通过生成器创建迭代器函数
let iterator = createIterator()
console.log(iterator.next().value);//1
console.log(iterator.next().value);//2
console.log(iterator.next().value);//3

  (2)函数表达式的生成器函数,使用函数表达式来创建一个生成器

        let myIterator = function* (items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
let myIterator1 = myIterator([1, 2, 3])
console.log(myIterator1.next().value);//1
console.log(myIterator1.next().value);//2
console.log(myIterator1.next().value);//3

  (3)对象类型的生成器函数

        var obj = {
createIterator: function* (item) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
}
// 也可以
var obj = {
*createIterator(items) {
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
}

  生成器会在每个yield 语句后停止执行,在函数中停止执行的能力是极其强大的,yield 关键字指定了迭代器在被调用next的方法是应当按顺序返回的值,在没有调用next() 方法的时候,生成器函数里的的代码并不会执行,同时也可用通过return 返回生成器函数的返回值,如下:

        function* generatorFn() {
console.log("start")
yield 'foo';
yield;
yield 'bar';
return 'baz';
}
let generatorObject = generatorFn();
console.log(generatorObject.next()); //start { done: false, value: 'foo' }
console.log(generatorObject.next()); // { done: false, value: undefined }
console.log(generatorObject.next()); // { done: false, value: 'bar' }
console.log(generatorObject.next()); // { done: true, value: 'baz' }

  3、 yield关键字详解

  (1) yield 关键字可以和值或者是表达式在一起使用,因此可以通过生成器给迭代器添加项目,而不是机械化地将项目一个个列出。

        // for循环内部使用yield关键字
function* createIterator2(items) {
//let 块级作用域
for (let i = 0; i < items.length; i++) {
yield items[i]
}
}
let iterator2 = createIterator2([1, 2, 3])
console.log(iterator2.next());//{value:1,done:false}
console.log(iterator2.next());//{value:2,done:false}
console.log(iterator2.next());//{value:3,done:false}
console.log(iterator2.next());//{value:undefined,done:true}

  注意 :yield 关键字只能用于生成器内部,用于其他位置会出现语法错误,即使在生成器内部的函数中也不行,下面的代码报错。

        // yield无法穿越函数边界,在一个嵌套函数中无法将值返回给包含它的函数
// function* createIterator2(items) {
// items.forEach(item => {
// yield item +1//语法错误
// });
// }

  (2) yield 关键字还可以作为函数的中间参数使用

  使用 yield 实现输入和输出, yield 关键字还可以作为函数的中间参数使用,上一次让生成器函数暂停的 yield 关键字会接收到传给 next() 方法的第一个值。第一次调用 next() 传入的值不会被使用,因为这一次调用是为了开始执行生成器函数

        function* generatorFn(initial) {
console.log(initial);
console.log(yield);
console.log(yield);
}
let generatorObject = generatorFn('foo');
generatorObject.next('bar'); // foo
generatorObject.next('baz'); // baz
generatorObject.next('qux'); // qux
// yield 关键字可以同时用于输入和输出,如下
function* generatorFn() {
return yield 'foo';
}
let generatorObject = generatorFn();
console.log(generatorObject.next()); // { done: false, value: 'foo' }
console.log(generatorObject.next('bar')); // { done: true, value: 'bar' }

  4、 yield* 委托给其他生成器或者可迭代对象

  (1)yield* 委托给其他可迭代对象

  可以使用星号增强 yield 的行为,让它能够迭代一个可迭代对象,从而一次产出一个值,因为 yield * 实际上只是将一个可迭代对象序列化为一连串可以单独产出的值,所以这跟把 yield 放到一个循环里没什么不同。下面两个生成器函数的行为是等价的:

        function* generatorFnA() {
for (const x of [1, 2, 3]) {
yield x;
}
}
console.log(generatorFnA());
for (const x of generatorFnA()) {
console.log(x);
}
// 1
// 2
// 3
function* generatorFnB() {
yield* [1, 2, 3];
}
for (const x of generatorFnB()) {
console.log(x);
}
// 1
// 2
// 3

  (2)yield* 委托给其他生成器

        function* createNumberIterator() {
yield 1;
yield 2;
return 3;
}
function* createRepeatingIterator(count) {
for (let i = 0; i < count; i++) {
yield "repeat";
}
}
function* createCombinedIterator() {
let result = yield* createNumberIterator();
yield result;
yield* createRepeatingIterator(result);
} var iterator = createCombinedIterator();
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: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  上面的代码中createCombinedIterator()生成器委托了 createNumberIterator 生成器,并将它的返回值赋值给了result变量,yeild result 输入该变量值3,result变量接下来作为参数传递 createRepeatingIterator()生成器,提示同一字符串需要调用3次。

写在最后

  以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。

js--生成器总结的更多相关文章

  1. 使用express.js框架一步步实现基本应用以及构建可扩展的web应用

    最近过年在家有点懈怠,但是自己也不断在学习新的前端技术,在家琢磨了express.js的web框架. 框架的作用就是提高开发效率,快速产出结果.即使不使用框架,我们也会在开发过程中逐渐形成构成框架. ...

  2. 如何使用swfobject(中文版)

    1.SWFObject是什么? SWFObject 2提供两种优化flash播放器的嵌入方法:基于标记的方法和依赖于js的方法. SWFObject 2提供一个js的API,为嵌入SWF文件和获取Fl ...

  3. 第四篇 express 安装esasticsearch

    1.首先,我们创建一个Express应用程序!我将使用express.js生成器. npm install -g express-generator express ./autocompleter c ...

  4. express搭建elasticsearch

    1.首先,我们创建一个Express应用程序!我将使用express.js生成器. npm install -g express-generator express ./autocompleter c ...

  5. [Node.js] ECMAScript 6中的生成器及koa小析

    原文地址:http://www.moye.me/2014/11/10/ecmascript-6-generator/ 引子 老听人说 koa大法好,这两天我也赶了把时髦:用 n 安上了node 0.1 ...

  6. js数组的内部实现,迭代器,生成器和内包

    js内部实现 在js以外的很多语言中,数组将会隐式占用一段连续的内存空间.这种隐式的内部实现,使得高效的内存使用及高速的元素方法称为可能,而 在javascript中,数组实体是一个对象,所以通常的实 ...

  7. js页码生成库,一个适合前后端分离的页码生成器

    原文:js页码生成库,一个适合前后端分离的页码生成器 前言 上星期写的任务里面有需要进行分页的处理,git搜索了一番,没有觉得合适的,于是自己临时写了个分页的算法. 然后等闲下来的时候,决定把分页进行 ...

  8. [js高手之路] es6系列教程 - 迭代器与生成器详解

    什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...

  9. [js高手之路] es6系列教程 - 迭代器,生成器,for...of,entries,values,keys等详解

    接着上文[js高手之路] es6系列教程 - 迭代器与生成器详解继续. 在es6中引入了一个新的循环结构for ....of, 主要是用来循环可迭代的对象,那么什么是可迭代的对象呢? 可迭代的对象一般 ...

  10. 只要三步,使用html5+js实现像素风头像生成器

    只要三步,使用html5+js实现像素风头像生成器 html5的画布给我们带来了很大的空间,其实像素风格头像生成器只是用到了画方块的方法.画一个像素头像,只要三步,1.解决像素点,2.解决像素点之间的 ...

随机推荐

  1. Python基础(序列化)

    #pickling import pickle,json # d = dict(name='傻狗1',age=300,score=100) # d1 = pickle.dumps(d)#pickle. ...

  2. Android SeekBar 自定义thumb,thumb旋转动画效果

    简介 某些音乐播放或者视频播放的界面上,资源还在加载时,进度条的原点(thumb)会显示一个转圈的效果. 资源加载完成后,又切换回静态效果.这个效果增强了用户体验. 一般来说有美术人员负责设计和切图. ...

  3. [atAGC004F]Namori

    考虑树的情况,将其以任意一点为根建树 对于每一个节点,考虑其要与父亲操作几次才能使子树内均为黑色,这可以用形如$(0/1,x)$的二元组来描述,其中0/1即表示其要求操作时父亲是白色/黑色且要操作$x ...

  4. [spojQTREE5]Query on a tree V

    合理的正解大概是动态点分治,这里给出其实现 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 st ...

  5. [hdu6582]Path

    首先,从1和n跑一次dij,判断每一条边能否出现在最短路上,不能出现就删掉,然后将所有边建在图上,流量为边权,跑最小割即可. 1 #include<bits/stdc++.h> 2 usi ...

  6. [atAGC014E]Blue and Red Tree

    不断删除重边,然后将两个点的边集启发式合并(要考虑到两棵树),合并时发现重边就加入队列,最后判断是否全部删完即可 1 #include<bits/stdc++.h> 2 using nam ...

  7. [loj3300]组合数问题

    将$f(k)=\sum_{i=0}^{m}a_{i}k^{i}$转换为$f(k)=\sum_{i=0}^{m}b_{i}k^{\underline{i}}$,其中$k^{\underline{i}}= ...

  8. [luogu5423]Valleys

    先考虑不要求有洞,那么可以将所有权值排序,然后不断插入,那么一个连通块就是一个答案,加上连通块大小即可考虑并查集如何判断是否有洞,可以发现对于任意一个无洞的直角多边形,都有$90度内角-90度外角=4 ...

  9. java 必应壁纸批量下载

    基于java 必应壁纸批量下载 - rookie丶k - 博客园 (cnblogs.com)实现 上面代码运行本地有点小问题,改了改 1.ssl验证 2.请求头 3.需要优化下载速度,多线程方式(还不 ...

  10. 如何查看dpdk版本

    服务器上曾经装过很多版本的dpdk,此时如果编译某个程序出现奇怪错误的时候不由得会怀疑是不是dpdk版本的问题= = 令人吃惊的是,网上搜了一圈居然没有一个简单直接的方法能够直接使用,于是自己实验了一 ...