ES6基础:Generator生成器
Posted 余光、
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ES6基础:Generator生成器相关的知识,希望对你有一定的参考价值。
Generator 生成器
Generator是一种奇特的函数形式,因为它的语法行为与传统函数完全不同,在平时项目中的使用频率也很低,大家经常将它忽略,甚至没有了解过,毕竟不熟悉它对日常开发也影响不大。
本文不会去深究它的实现原理,而是希望让大家了解到它被创造出来是为了解决什么问题,我们用它可以做什么?
一、了解生成器
生成器可以在执行当中暂停自身,可以立即恢复执行也可以过一段时间之后恢复执行。所以显然它并不像普通函数那样保证运行到完毕。
1.1 特征
生成器是一个状态管理的机器,内部可以保存若干个状态,且状态与状态之间需要手动触发。
简单的理解:它就是一种特别的函数,它包含两个特征:
function
关键字与函数名之间有一个星号;- 函数体内部使用 yield 表达式,定义不同的内部状态(yield 在英语里的意思就是“产出”)。
1.2 运行第一个生成器
function* generatorOne() {
yield 1;
return 2;
}
const g = generatorOne(); // Generator {<suspended>}
g.next(); // {value: 1, done: false}
g.next(); // {value: 2, done: true}
注意:
function *foo() {...}
,function* foo() {...}
,function * foo() {...}
都是生成器声明- 尽管生成器用 * 声明,但执行起来还和普通函数一样:
二、yield 关键字
生成器内有一个关键字 yield
,它是状态切换停止的标志。
2.1 运行逻辑
- 每次执行
next()
- 遇到yield 表达式,暂停执行后面的操作,yield紧跟着的表达式的值,作为返回的对象的value属性值;
- 如果没有遇到yield 表达式,就一直运行直到 return 语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值;
- 如果该函数没有return语句,则返回的对象的 value 属性值为 undefined。
需要注意的是,yield 表达式,只有当调用 next 方法、内部指针指向该语句时才会执行,因此等于为 javascript 提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。
2.2 实际使用
结合上一小节的文字描述,我们来逐步分析一下
function* generatorSleep(a, b) {
console.log(1);
console.log(2);
yield;
console.log(a + b);
return "结束";
}
const i = generatorSleep(100, 200); // 创建生成器
// 消费1次,暂停在第一个yield表达式,并且将表达式的值返回值对象的value属性中
i.next();
// 输出:1、2
// 返回:{ value: undefined, done: false }
// 消费1次,没有新的yield,遇到return,并且将表达式的值返回值对象的value属性中
i.next();
// 返回:{ value: '结束', done: false }
看了上面最后一行结果的同学可能会存在疑问,为什么第一次value
是undefiend
?
因为:紧跟在yield后面没有表达式,也没有返回值,value
自然是undefined
。
一个无限迭代器
function* foo() {
let index = 1;
while (true) {
yield index++;
}
}
const i = foo();
console.log(i.next().value); // 1
console.log(i.next().value); // 2
console.log(i.next().value); // 3
console.log(i.next().value); // 4
上面是一个生成器中的 while…true 循环,每次迭代都会 yield 表达式都会得到index这个结果。它表示执行的次数。
三、方法
3.1 next()
调用next()是改变状态的唯一方式
返回一个 yield 表达式生成的值。它是一个包含属性 done
和 value
的对象。该方法也可以通过接受一个参数用以向生成器传值。
下面就是它最常见的使用方式:
function* generator() {
const a = yield 1;
const b = yield 2;
return "结束了";
}
const i = generator(); // Generator
i.next(); // {value: 1, done: false}
i.next(); // {value: 2, done: false}
// 此时done 转变为true
i.next(); // {value: '结束', done: true}
next方法可以有参数
许多同学都会关心类似下面的代码,var x = yield 10;
,x会是什么?
function* foo() {
var x = yield 10;
console.log(x);
}
const i = foo();
i.next(); // {value: 10, done: false}
i.next();
// undefined
// {value: undefined, done: true}
x的值是undefined,这表示yield 10
本身没有返回值。为了给它指定返回值,我们可以这么做
function* gen() {
while (true) {
var value = yield null;
console.log(value);
}
}
var g = gen();
g.next(1);
// "{ value: null, done: false }"
g.next(2);
// 2
// "{ value: null, done: false }"
3.2 方法 return()
以下例子展示了一个简单的生成器和 return 方法的使用。
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next(); // { value: 1, done: false }
g.return("foo"); // { value: "foo", done: true }
g.next(); // { value: undefined, done: true }
注意:
- 如果对已经处于“完成”状态的生成器调用
return(value)
,则生成器将保持在“完成”状态。 - 如果没有提供参数,则返回对象的 value 属性与示例最后的.next()方法相同。
- 如果提供了参数,则参数将被设置为返回对象的 value 属性的值。
例如:
function* gen() {
yield 1;
yield 2;
}
var g = gen();
g.next(); // { value: 1, done: false }
g.next(); // { value: 2, done: false }
g.next(); // { value: undefined, done: true }
g.return(); // { value: undefined, done: true }
g.return(1); // { value: 1, done: true }
3.3 throw()
throw() 方法用来向生成器抛出异常,并恢复生成器的执行,返回带有 done 及 value 两个属性的对象。
function* gen() {
while (true) {
try {
yield 42;
} catch (e) {
console.log(e);
}
}
}
var g = gen();
g.next(); // { value: 42, done: false }
g.throw(new Error("Something went wrong")); // Error: Something went wrong
写在最后
- 花名:余光
- WX:j565017805
- 邮箱:webbj97@163.com
其他沉淀
以上是关于ES6基础:Generator生成器的主要内容,如果未能解决你的问题,请参考以下文章