ES6 新特性梳理系列丨Generator 函数

ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!


JavaScript 与 ECMAScript

JavaScript 诞生于1995年,设计者是就职于 Netscape 公司的工程师 Brendan Eich。它是一门仅用10天就完成设计的编程语言,但至今为止已对业界保持26年的影响,且势头愈发强劲

1996年 Netscape 将 JavaScript 提交给ECMA,希望它可以成为“标准化一个通用的、跨平台的、中立于厂商的脚本语言的语法和语义标准”,1997年 ECMA 确定将 JavaScript 作为浏览器脚本语言的标准,并为之重命名为 ECMAScript,所以通常来讲我们将 ECMAScript 视为 JavaScript 的标准,而 JavaScript 则是 ECMAScript 的实现及扩展

1997年-1999年连续发布了ES1-ES3发布,2000年开始酝酿新版本的升级内容,中间因标准委员会意见未能达成一致,只做了部分功能的小范围升级及支持,于2009年12月发布了过渡版 ECMAScript 5.0,2011年6月发布 ECMAScript 5.1 并成为 ISO 国际标准

2013年3月 ECMAScript 6 草案冻结,2013年12月 ECMAScript 草案发布,2015年6月 ECMAScript 6 正式通过,成为新的国际标准。ES6 泛指自2015年升级为 ECMAScript 6.0 后的所有子版本,如:ES2015-ES2020,等同于ES6.0-ES6.5,这是 JavaScript 走向企业级编程语言的强势升级

不断升级的标准与实现,对于开发效率及产品质量起到强有力的支撑,接下来我们开始梳理ES6的新特性吧!


什么是 Generator 函数

在传统函数中,函数一旦开始执行,就会运行到结束或者遇到 return 语句提前结束,期间不会有其他的语句能够终止函数的执行,而 Generator 函数可以在函数运行期间暂停,也就是打破函数的完整运行。

实际上他是 ES6 提出的一种异步编程解决方案,旨在实现在JS中优雅的实现异步编程,避免回调地狱现象。


创建一个 Generator

function * test() {
  yield  'a';
  yield  'b';
  return  'c';
}
var gene = test()


gene.next()
// {value:'a',done:false}
gene.next()
// {value:'b',done:false}
gene.next()
// {value:'c',done:true}
gene.next()
// {value:undefined,done:true}

上面代码中,通过 function * ,创建一个 Generator 函数,在函数体内使用yield 语句,为 Generator 函数定义了不同的内部状态,a,b和c三个状态。

Generator 函数的执行返回的是一个 iterator 对象,我们通过 next() 方法可以依次遍历 generator 中的多个状态,yield 语句后面的表达式的值,作为next 语句返回的 value 值输出。

可以这样认为,yield 语句像是在 generator 函数里防止了很多个暂停点,而next 语句可以恢复暂停点的执行。

funtion 关键字和函数名之间的星号,放在哪里都可以,也就是下面这四种写法都正确。

function* test() {...}
function * test() {...}
function *test() {...}
function*test() {...}

有关 iterator 遍历器的详细信息,请移步本系列文章ES6 新特性梳理系列丨Iterator 和 for...of 循环


yield语句

我们来回顾一下上面的 test 函数。

当第一次调用 next() 时,遇到了第一个 yield 语句,将第一个 yield 语句后面的 'a' 作为返回的对象的 value 属性值;

第二次调用 next() 遇到了第二个 yield 语句,将第一个 yield 语句后面的 'b' 作为返回的对象的 value 属性值;

第三次调用 next() ,没有遇到 yield 语句,我们遇到了 return 语句,将 return 语句后面的 'c' 作为返回的对象的 value 值,并且将 done 设为 true,表示 generator 中的状态已经遍历结束了;

第四次调用 next(),此时后面已经没有 yield 和 return 了,我们返回的对象的 value 为 undefined,done 为 true。

值得注意的是,yield 后面的表达式,并不会立即执行,只有当手动调用next() 函数时才会执行。一个 generator 函数中,可以包含多个 yield 语句,但只能包含一个 return 语句。


next()

需要注意,yield 语句并没有返回值,或者说总是返回 undefined。注意不要和上面所说的弄混,yield 语句后面的表达式将会作为 next() 函数返回的对象的 value 属性值,和这里 yield 语句本身并无返回值是两个概念。

next() 方法可以包含一个参数,这个参数将会作为上一个 yield 语句的返回值。

我们引入一个例子进行说明:

function * test(x) {


  var y = yield(x+1)
  var z = yield(y+1)
  return x+y+z
}


var a = test(2);
a.next() // Object{value:3, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}


var b = test(2);
b.next() // { value:3, done:false }
b.next(5) // { value:6, done:false }
b.next(10) // { value:17, done:true }

上面代码中,先说上半部分。var a = test(2),为x赋值2,那么返回的值就是2+1,为3;再次调用 next(),执行第二个 next(),此时由于yield语句返回的值为 undefined,所以 y+1,等同于 undefined + 1,返回 NaN ;再次调用next(),执行 return 语句,由于第二个yield语句返回值为 undefined,所以x+y+z,等同于 3+undefined+undefined,返回 NaN。

再说下半部分,var b = test(2),为x赋值2,第一次调用,那么返回的值就是2+1,为3;第二次调用 next(),参数5作为第一个 yield 语句的返回结果,也就相当于 var y = 5,则第二个 yield 语句中的表达式就变成  yield(5+1),返回6;第三次调用 next(),执行 return 语句,参数10作为第二个 yield语句的返回结果,也就相当于 var z = 10 ,最终执行结果相当于 return 2+5+10,结果为17。

注意,由于 next 方法的参数作为上一个 yield 语句的返回值,所以第一个next 方法不能带有参数,即使带了,JS 也会自动忽略第一个 next 方法的参数。


for...of循环


我们上一篇讲过,for...of 循环专门为 iterator 遍历器而生,而 generator 函数相当于一个 iterator 生成器,所以 for...of 循环可以自动遍历 generator 函数,并且不需要调用 next 方法。

 function * test() {
  yield 1;
  yield 2;
  return 3;
}


for (let i of test()) {
  console.log(i);
}
// 1 2

需要注意的是,generator 函数中的 return 语句执行时,返回对象中的 done 为 true,而 for...of 循环遇到返回对象的 done 为 true,就会立即终止循环,所以遍历返回结果并不包含 return 语句中的3。


yield* 语句

当我们在一个 generator 函数内部调用另一个 generator 函数时,就要使用yield* 语句。

function * test1() {
  yield '1';
  yield '2';
}


function * test2() {
  yield * test1(); 
  yield '3';
  yield '4';
}
for (let i of test2()){
  console.log(i);
}
// 1 2 3 4

ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!

叶阳辉

HFun 前端攻城狮

往期精彩:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值