[JavaScript]ECMA-6 yield语法
概述
yield关键字用于并且仅限于生成器函数(generator)内部,作用是暂停(并返回)/重启(可选修改该栈环境变量)该函数栈环境。
一般语法
调用生成器函数时返回一个可迭代对象,当调用该对象的next()方法时,函数会在遇到yield关键字的位置马上返回一个IteratorResult对象,该对象格式如下:
{value: [Mixed], done: [boolean]}
yield的行为类似于return,不同的地方在于,yield返回后并不等同于该次函数调用的结束,该函数的栈环境仍然存在于内存当中(暂停),等待下一次调用到来时,代码段将会在上一次yield返回的位置继续往下执行(重启),
这样就实现了函数的暂停/重启行为。
function* foo(index) {
let a = 2;
while (index < a) {
c = yield index++;
}
}
const iterator = foo(0);
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
输出:
{value: 0, done: false}
{value: 1, done: false}
{value: undefined, done: true}
可见每次调用next()都会在yield处返回该变量的结果并不再往下执行,当下次调用next()时,该函数会在上一次yield的位置继续往下执行,直到函数真正执行完毕,返回对象的done属性被赋值为true。
改变函数内部变量
yield还有另外一种能力,就是改变该函数栈内变量的值。
[rv] = yield [expression];
调用next()时接受一个参数
generator.next([vaule]);
这样多次调用(除第一次)时,就会先把vaule赋值给函数内部变量rv再继续往下执行
示例:
function* foo(index) {
let a = 2;
var b;
while (index < a) {
b = yield b;
}
}
const iterator = foo(0);
console.log(iterator.next('a'));
console.log(iterator.next('b'));
console.log(iterator.next('c'));
输出:
{value: undefined, done: false}
{value: "b", done: false}
{value: "c", done: false}
当yield前加=号赋值给函数内部某个变量时,在第一次调用将不会给该变量赋予任何形式的值,所以在这里的第一行输出时,value等于undefined,并不是设想的被赋值为a。让next([vaule])真正起作用,是在多次调用的时候,在重启函数时,先把该函数栈内的rv变量赋值为value后再继续执行。这有点类似于Python的nex()和send(),只不过ECMA-6只用了next()来实现这种功能。
这里有一个难点,就是难以理解rv是何时改变它的值的,为了更清晰的说明这个问题,我们更改一下上面的例子,在yield前输出一下变量b
function* foo(index) {
let a = 2;
var b;
while (index < a) {
console.log(b);
b = yield b;
}
}
const iterator = foo(0);
console.log(iterator.next('a'));
console.log(iterator.next('b'));
console.log(iterator.next('c'));
输出:
undefined
{value: undefined, done: false}
b
{value: "b", done: false}
c
{value: "c", done: false}
可以看见,每次调用在yield <statement>执行完成后,不管接下来是任何代码,函数都会暂停,包括return yield <statement>。示例代码中第一次调用:
console.log(b);//因为b确实还没有被赋值,输出undefined还是比较容易理解的
b = yield b;//yield b返回b的值给IteratorResult对象,这时b依然是没有任何赋值的,所以也是undefined。并且执行完yield b后函数马上暂停
直到第二次调用
iterator.next('b');
这时调用函数next()传入值"b","b"被赋值到变量b,代码继续往下执行,由于是一个循环语句,于是代码又来到了
console.log(b);//此时b已经被赋了值,所以输出"b"
b = yield b;//yield b也返回b的值给IteratorResult对象,这时b依然是"b",然后马上暂停,等待下一次调用
return yield
有一种情况,就是该类函数如果包含return语句又会怎样呢?我们来看看MDN对这个行为的描述:
- A
returnstatement is reached. In this case, execution of the generator ends and anIteratorResultis returned to the caller in which thevalueis the value specified by thereturnstatement anddoneistrue.
如预料之中的一样,return会终止函数,并返回return语句的结果,放置在IteratorResult.vaule上,同时这也意味着整个迭代结束,IteratorResult.done为true.
但是,如果是return yield [statement]呢?来看看下面的例子:
function* foo(index) {
let a = 3;
while (index < a) {
return yield index++;
}
}
const iterator = foo(0);
console.log(iterator.next('a'));
console.log(iterator.next('b1'));
console.log(iterator.next('c'));
输出:
{value: 0, done: false}
{value: "b1", done: true}
{value: undefined, done: true}
如果结合上小段介绍,即“改变函数内部变量”,就不难理解这个例子的行为;
在第一次调用,next()返回未经递增的index,即0,并且暂停函数;
第二次调用,重启函数,把参数的值"b1"赋值给函数栈环境的变量,但是由于这里遇到的是return,所以"b1"自然而然的返回给了IteratorResult.vaule,并且结束整个迭代;
第三次调用,由于迭代已经结束,所以这里的调用已经没有任何意义;
[JavaScript]ECMA-6 yield语法的更多相关文章
- JavaScript学习02 基础语法
JavaScript学习02 基础语法 JavaScript中很多基础内容和Java中大体上基本一样,所以不需要再单独重复讲了,包括: 各种算术运算符.比较运算符.逻辑运算符: if else语句.s ...
- JavaScript学习之路-语法
版权声明:未经博主允许不得转载 在JavaScript中如何写语法呢?这里你可以去看一些教学文档来得快一些,这里不介绍,有点基础的也可以复习一下. //定义变量并赋值 var a; //定义变量 va ...
- yield 语法备忘录
yield 语法备忘录 yield 语法备忘录 语法 .net yield 读作:“一有得” 英式发音 皮一下~ yield 关键字向编译器指示它所在的方法是迭代器块. 编译器生成一个类来实现 ...
- 在JavaScript中实现yield,实用简洁实现方式。
原题还是老赵的: http://blog.zhaojie.me/2010/06/code-for-fun-iterator-generator-yield-in-javascript.html 原以为 ...
- JavaScript基础(一)之语法、变量、数据类型
1.JavaScript语法 ①区分大小写 ②弱类型变量 ③每行结尾分号可有可无 ④括号用于代码块 ⑤注释有两种方式(单行和多行注释) 2.JavaScrip变量 ①用Var声明,不要初始化 ②可以在 ...
- (转)JavaScript二:JavaScript语言的基本语法要求
摘自:http://blog.csdn.net/erlian1992 要学习好JavaScript,首先我们要懂JavaScript语言的一些基本语法要求: 一,区分大小写 JavaScript语言区 ...
- JavaScript学习笔记-基础语法、类型、变量
基础语法.类型.变量 非数字值的判断方法:(因为Infinity和NaN他们不等于任何值,包括自身) 1.用x != x ,当x为NaN时才返回true; 2.用isNaN(x) ,当x为NaN或 ...
- javascript简介和基本语法
javascript简介 1.javascript是个脚本语言,需要有宿主文件,他的宿主文件是html文件. 用法:为了保险起见一般写在</html>之后<javascript ...
- 4、JavaScript进阶篇①——基础语法
一.认识JS 你知道吗,Web前端开发师需要掌握什么技术?也许你已经了解HTML标记(也称为结构),知道了CSS样式(也称为表示),会使用HTML+CSS创建一个漂亮的页面,但这还不够,它只是静态页面 ...
随机推荐
- 早上一起来,就看到朋友圈发这个,慌的一 B
早上一起来,就看到朋友圈发这个,慌的一 B,也不知道是真是假- 图中的 c 表示已被确认,大家可以看到各个大厂真的是在大幅度裁员. 不知道明年的情况会如何,网上看到过一句话:2019 年也许是这 10 ...
- codeforces gym #102082C Emergency Evacuation(贪心Orz)
题目链接: https://codeforces.com/gym/102082 题意: 在一个客车里面有$r$排座位,每排座位有$2s$个座位,中间一条走廊 有$p$个人在车内,求出所有人走出客车的最 ...
- Python中数学函数
1.不需要引入math模块的有: abs(),cmp(),max(),min(),pow(),round() 2.需要引入math模块的: 三角函数,及其他数学函数,fabs(), *需要特别注意: ...
- Linux -- nginx
一. 网络服务 web服务器和web框架的关系 web服务器(nginx):接收HTTP请求(例如www.baidu.com)并返回数据 web框架(django,flask):开发web应用程序,处 ...
- python爬虫爬取赶集网数据
一.创建项目 scrapy startproject putu 二.创建spider文件 scrapy genspider patubole patubole.com 三.利用chrome浏览器 ...
- css高度自適應
高度自適應意思是高度能隨著瀏覽器的大小的變化而變化.
- Docker 删除容器日志
在使用docker的时候,我们经常通过 docker logs -f containername或者id 但是有时候日志很多.很麻烦.所以需要清理一下对应container的日志. 默认情况下,dao ...
- 【转】Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印。
@2019-02-28 [小记] Esp8266学习之旅① 搭建开发环境,开始一个“hellow world”串口打印.
- [欢乐向]JavaScript之如何逼疯你的同事
https://javascript.info/ninja-code
- JSON三种数据解析方法(转)
原 JSON三种数据解析方法 2018年01月15日 13:05:01 zhoujiang2012 阅读数:7896 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blo ...