当前位置:网站首页>ES6深入—ES6 Generator 函数
ES6深入—ES6 Generator 函数
2022-07-05 15:27:00 【橘猫烧鲷鱼ᅟᅠ】
前言
ES6 新增了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,从而可以改变执行流程,或者可以暂停或者延迟执行,这也就为异步编程提供解决方案。
基本用法将在本文当中讲解。
一、Generator 函数组成
Generator 有两个方面和普通函数不一样:
function 后面,函数名之前有个 * ;
函数的内部有 yield 表达式。
其中 * 用来表示 Generator 函数,yield 用来定义函数内部的状态。
function* call() {
console.log("first");
yield "1";
console.log("second");
yield "2";
console.log("third");
return "3";
}
二、Generator 函数执行机制
使用 Generator 函数,和一般函数一样,是在函数名后面加上 (),但是 Generator 函数不会像普通函数那样马上执行,而是会返回一个指针,这个指针指向对象的内部状态,所以要调用遍历器对象 Iterator 的 next 方法,指针就会从函数头部或者上一次停下来的地方开始执行。
f.next();
// one
// {value: "1", done: false}
f.next();
// two
// {value: "2", done: false}
f.next();
// three
// {value: "3", done: true}
f.next();
// {value: undefined, done: true}
详细解释如下说明:
第一次调用 next 方法时,从 Generator 函数的头部开始执行,先是打印了 first,执行到 yield 就停下来,并将 yield 后边表达式的值 ‘1’,作为返回对象的 value 属性值,此时函数还没有执行完,返回对象的 done 属性值是 false。
第二次调用 next 方法时,和第一次一样。
第三次调用 next 方法时,先是打印了 third,然后执行了函数的返回操作,并将 return 后面的表达式的值,作为返回对象的 value 属性值,此时函数已经结束,所以 done 属性值为 true。
最后调用 next 方法时,此时函数已经执行完了,所以返回 value 属性值是 undefined ,done 属性值是 true。如果执行第三步时,没有 return 语句的话,就直接返回 {value: undefined, done: true}。
创建名称为 es6gen4.js 的文件,并且输入下面的代码。
function* call() {
console.log("first");
yield "1";
console.log("second");
yield "2";
console.log("third");
return "3";
}
var f = call();
f.next();
f.next();
f.next();
f.next();
在终端输入 node es6gen4.js 运行,结果如下所示:
三、函数返回的遍历器对象的方法
next 方法
常规情况,next 方法不传入参数时候,yield 表达式的返回值是 undefined。当 next 传入参数的时候,这个参数会作为上一步 yield 的返回值。
function* make2Parameter() {
console.log("开始");
var x = yield "2";
console.log("第一个:" + x);
var y = yield "3";
console.log("第二个:" + y);
console.log("全部是:" + (x + y));
}
next 不传参的情况如下:
var cost = make2Parameter();
cost.next();
// 开始
// {value: "2", done: false}
cost.next();
// 第一个:undefined
// {value: "3", done: false}
cost.next();
// 第二个:undefined
// 全部是:NaN
// {value: undefined, done: true}
next 传参情况:
var cost2 = make2Parameter();
cost2.next(10);
// 开始
// {value: "2", done: false}
cost2.next(20);
// 第一个:20
// {value: "3", done: false}
cost2.next(30);
//第二个:30
// 全部:50
// {value: undefined, done: true}
创建 名称为 es6gen5.js 的文件,并且输入下面的代码。
function* make2Parameter() {
console.log("开始");
var x = yield "2";
console.log("第一个:" + x);
var y = yield "3";
console.log("第二个:" + y);
console.log("全部是:" + (x + y));
}
var cost = make2Parameter();
cost.next();
// 开始
// {value: "2", done: false}
cost.next();
// 第一个:undefined
// {value: "3", done: false}
cost.next();
// 第二个:undefined
// 全部是:NaN
// {value: undefined, done: true}
var cost2 = make2Parameter();
cost2.next(10);
// 开始
// {value: "2", done: false}
cost2.next(20);
// 第一个:20
// {value: "3", done: false}
cost2.next(30);
//第二个:30
// 全部:50
// {value: undefined, done: true}
运行结果如下:
除了使用 next,还可以使用 for… of 循环遍历 Generator 函数生产的 Iterator 对象。
return 方法
return 方法返回给定的值,并结束遍历 Generator 函数。return 方法提供参数时,返回该参数;不提供参数时,返回 undefined。
function* call() {
yield 1;
yield 2;
yield 3;
}
var f = call();
f.next();
// {value: 1, done: false}
f.return("foo");
// {value: "foo", done: true}
f.next();
// {value: undefined, done: true}
throw 方法
throw 方法可以再 Generator 函数体外面抛出异常,再函数体内部捕获。
另外一个例子:
var d = function* () {
try {
yield;
} catch (e) {
console.log("捕获里面的错误", e);
}
};
var i = d();
i.next();
try {
i.throw("a");
i.throw("b");
} catch (e) {
console.log("捕获外面的错误", e);
创建名称为 es6gen6.js 的文件,并且输入下面的代码。
var d = function* () {
try {
yield;
} catch (e) {
console.log("捕获里面的错误", e);
}
};
var i = d();
i.next();
try {
i.throw("a");
i.throw("b");
} catch (e) {
console.log("捕获外面的错误", e);
}
运行结果如下:
遍历器对象抛出了两个错误,第一个被 Generator 函数内部捕获,第二个因为函数体内部的 catch 函数已经执行过了,不会再捕获这个错误,所以这个错误就抛出 Generator 函数体,被函数体外的 catch 捕获。
yield*
表达式
yield* 表达式用于表示 yield 返回一个遍历器对象,用于在 Generator 函数内部,调用另一个 Generator 函数。
function* callA() {
console.log("callA: " + (yield));
}
function* callerB() {
while (true) {
yield* callA();
}
}
const callerObj = callerB();
callerObj.next();
callerObj.next("first");
callerObj.next("second");
创建名称为 es6gen7.js 的文件,并且输入下面的代码。
function* callA() {
console.log("callA: " + (yield));
}
function* callerB() {
while (true) {
yield* callA();
}
}
const callerObj = callerB();
callerObj.next();
callerObj.next("first");
callerObj.next("second");
运行效果如下:
上面的案例代码可以用下面的代码代替(效果相同):
// 等同于
function* callerB() {
while (true) {
for (var value of callA) {
yield value;
}
}
}
四、使用场景
实现 Iterator
为不具备 Iterator 接口的对象提供遍历方法。
function* objEnter(obj) {
const propKeys = Reflect.ownKeys(obj);
for (const propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
const jane = {
first: "小A", last: "大D" };
for (const [key, value] of objEnter(jane)) {
console.log(`${
key}: ${
value}`);
}
// first: 小A
// last: 大D
完整案例如下:
创建 名称为 es6gen8.js 的文件。输入下列代码:
function* objEnter(obj) {
const propKeys = Reflect.ownKeys(obj);
for (const propKey of propKeys) {
yield [propKey, obj[propKey]];
}
}
const jane = {
first: "小A", last: "大D" };
for (const [key, value] of objEnter(jane)) {
console.log(`${
key}: ${
value}`);
}
// first: 小A
// last: 大D
运行效果:
Reflect.ownKeys() 返回对象所有的属性,不管属性是否可枚举,包括 Symbol。 javascript 原生是不具备 Iterator 接口无法通过 for… of 遍历。这边用了 Generator 函数加上了 Iterator 接口,所以就可以遍历 jane 对象了。
总结
本文介绍了 ES6 Generator 函数的概念和使用。以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。
边栏推荐
- Lesson 4 knowledge summary
- Object. defineProperty() - VS - new Proxy()
- 16. [stm32] starting from the principle, I will show you the DS18B20 temperature sensor - four digit digital tube displays the temperature
- Verilog realizes the calculation of the maximum common divisor and the minimum common multiple
- 具有倍数关系的时钟切换
- 事务回滚异常
- Usage and usage instructions of JDBC connection pool
- lv_font_conv离线转换
- I'm fat, huh
- ICML 2022 | explore the best architecture and training method of language model
猜你喜欢
19.[STM32]HC_SR04超声波测距_定时器方式(OLED显示)
SQL Server learning notes
F. Min cost string problem solving Report
Data communication foundation smart_ Link_&_ Monitor_ Link
Usage and usage instructions of JDBC connection pool
Advanced level of static and extern
Clock switching with multiple relationship
Detailed explanation of C language branch statements
Intelligent metal detector based on openharmony
Replknet: it's not that large convolution is bad, but that convolution is not large enough. 31x31 convolution. Let's have a look at | CVPR 2022
随机推荐
Data communication foundation - routing communication between VLANs
Go learning ----- relevant knowledge of JWT
基于OpenHarmony的智能金属探测器
How difficult is it to pass the certification of Intel Evo 3.0? Yilian technology tells you
Appium automation test foundation - appium basic operation API (II)
vant tabbar遮挡内容的解决方式
Data communication foundation NAT network address translation
SQL injection sqllabs (basic challenges) 11-20
Temporary cramming before DFS examination
lvgl 显示图片示例
五种常见的咨询公司谈判策略以及如何维护自己的利益
This article takes you through the addition, deletion, modification and query of JS processing tree structure data
复现Thinkphp 2.x 任意代码执行漏洞
MySQL 巨坑:update 更新慎用影响行数做判断!!!
Reproduce ThinkPHP 2 X Arbitrary Code Execution Vulnerability
一文搞定vscode编写go程序
MySQL table field adjustment
lv_ font_ Conv offline conversion
Severlet learning foundation
ICML 2022 | explore the best architecture and training method of language model