原创

深入了解js中的yield


什么是yield

yield是ES6的新关键字,使生成器函数执行暂停,yield关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的return关键字。

yield关键字实际返回一个IteratorResult(迭代器)对象,它有两个属性,value和done,分别代表返回值和是否完成。

yield无法单独工作,需要配合generator(生成器)的其他函数,如next,懒汉式操作,展现强大的主动控制特性。

一个简单的例子

  function* myYield(list) {
    for (let i = 0; i < list.length; i++) {
      yield list[i]
    }
  }
  const numList = myYield([1,4,8])
  console.log(numList.next())//{done: false,value: 1}
  console.log(numList.next())//{done: false,value: 4}
  console.log(numList.next())//{done: false,value: 8}
  console.log(numList.next())//{done: true,value: undefined}

一个简单的迭代

  for (let n = numList.next(); !n.done; n=numList.next()) {
    console.log(n.value)
  }

简单概括,每次执行next(),都会执行一个yield返回的值

yield可以用来加强控制,懒汉式加载

调用函数指针和调用生成器是两码事

需要next()函数配合使用,每次调用返回两个值:分别是value和done,代表迭代结果和是否完成

函数next()是个迭代器对象,传参可以缺省,默认调用函数

说明

1.yield并不能直接生产值,而是产生一个等待输出的函数

2.除IE外,其他所有浏览器均可兼容(包括win10 的Edge)

3.某个函数包含了yield,意味着这个函数已经是一个Generator

4.如果yield在其他表达式中,需要用()单独括起来

5.yield表达式本身没有返回值,或者说总是返回undefined(由next返回)

6.next()可无限调用,但既定循环完成之后总是返回undeinded

关于next参数的说明

function* myYield2(x) {
  let y = 2*(yield (x+1));
  yield (y+3);
}
var num = myYield2(3)
console.log(num.next())//{value: 4, done: false}
console.log(num.next())//{value: NaN, done: false}

以上代码解析

1.var num = myYield2(3) 执行了初始化,x为3

2.执行【第一个next()】相当于执行了yield (x+1) 而x为3,所以返回value为4,

3.又因为当前确实执行了yield语句,所以返回的done为false

4.接下来【执行第二个next()】,因为yield没设定返回值,

5.所以let y = 2*(undefined) 结果y为NaN

6.之后执行yield (NaN+3) 结果为NaN

再解析以下代码

function* myYield2(x) {
  let y = 2*(yield (x+1));
  let z = yield (y+3);
  return (x+y+z)
}
var num = myYield2(3)
console.log(num.next())//{value: 4, done: false}
console.log(num.next(2))//{value: 7, done: false}
console.log(num.next(2))//{value: 9, done: false}
console.log(num.next(2))//{value: undefined, done: true}

1.var num = myYield2(3) 执行了初始化,x为3

2.执行【第一个next()】,相当于执行了yield (x+1) 而x为3,所以返回value为4

传参不传参都无所谓,因为传的参数只是代替上面yield的值,第一个之前没有其他的yield

3.执行【第二个next(2)】,相当于let y = 2*(2); 结果y=4;yield (y+3);相当于yield (4+3) 最终结果返回7

执行【第三个next(2)】,相当于执行了let y = 2*(2);let z = 2;return (3+4+2);最终结果return也可以认为是一个yield,如:

function* myYield2(x) {
  let y = 2*(yield (x+1));
  let z = yield (y+3);
  yield (x+y+z)
}
var num = myYield2(3)
console.log(num.next())//{value: 4, done: false}
console.log(num.next(2))//{value: 7, done: false}
console.log(num.next(2))//{value: 9, done: false}
console.log(num.next(2))//{value: undefined, done: true}

4.【第四个next(2)】,已经没有yield了,终结结果

如果代码是这样呢?

function* myYield2(x) {
  let y = 2*(yield (x+1));
  return (y+3);
  yield (x+y)
}

很显然,return以后的yield全部都将作废,等于不存在

总结yield的参数

next() 传参是对yield整体的传参,否则yield类似于return

当yield在赋值表达式的右边,比如 var result = yield 4 ,记住这句话,yield语句本身没有返回值,或者说返回值是undefined,但是当我们调用next(param)传参的时候,param不但作为next返回对象的value值,它还作为上一条yield 的返回值,所以result 才会被成功赋值。

JavaScript
ES6
  • 作者:零三(联系作者)
  • 最后更新时间:2020-08-10 17:24
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 转载声明:来源地址 https://web03.cn