zl程序教程

您现在的位置是:首页 >  前端

当前栏目

【笔记】再学JavaScript ES(6-10)全版本语法——Generator(案例:抽奖&斐波那契数列)

JavaScriptESamp案例笔记 版本 10 语法
2023-09-27 14:26:51 时间


Generator(生成器)

1.引入案例:让遍历停下来

ES5

function loop () {
  for (let i = 0; i < 5; i++) {
    console.log(i)
  }
}
loop()

ES6

function * loop () {
  for (let i = 0; i < 5; i++) {
    yield console.log(i)
  }
}
const l = loop()
l.next()
l.next()
l.next()

2.Next

  • Generator函数函数名之前需要加 *
  • 在需要控制的语句前加 yield
  • 可嵌套使用
  • Generator对象调用next函数来执行被控制的语句,执行时返回yield后面表达式的返回值和Generator对象执行状态
function * f () {
  yield console.log(1)
  yield console.log(2)
  let val
  console.log(val = yield [1, 2, 3]) // val,将整个yield表达式的值替换为next的参数
  console.log(yield val) // 10,整个yield表达式的值,即传给next的参数
}

const l = f()
console.log(l.next(10)) // {value: undefined, done: false} 第一个yield后面表达式的返回值
console.log(l.next(10)) // {value: undefined, done: false} 第二个yield后面表达式的返回值
console.log(l.next(10)) // {value: Array(3), done: false} 第三个yield后面表达式的返回值
console.log(l.next({ 'A': 'a', 'B': 'b' })) // {value: {A: "a", B: "b"}, done: false} 将参数传递给整个yield表达式并完成
console.log(l.next(10)) // {value: undefined, done: true}
/**
 * 只有当整个Generator函数执行完毕(最后一个yield执行完毕),状态done才会置为true(其实返回的是上一个next执行完后的状态)
 */

3.Return

function * f () {
  yield console.log(1) // 1
  yield console.log(2)
  let val
  console.log(val = yield [1, 2, 3])
  console.log(yield val)
}

const l = f()
console.log(l.next('next')) // {value: undefined, done: false}
console.log(l.return('return')) // {value: "return", done: true}, 类似return关键字,参数直接影响最终return函数的返回值

4.Throw

function * f () {
  try {
    yield console.log(1) // 1
    yield console.log(2)
    yield console.log(3)
  } catch (e) {
    console.log(e.message) // throw
  } finally {
    let val
    console.log(val = yield [1, 2, 3]) // yield表达式的值——next的参数‘next’
    console.log(yield val) // yield表达式的值——next的参数‘next’
  }
}

const l = f()
console.log(l.next('next')) // {value: undefined, done: false}
console.log(l.throw(new Error('throw'))) // {value: Array(3), done: false},如果所执行代码外没有try catch就抛出异常,报错,直接中断
console.log(l.next('next')) // {value: "next", done: false},返回值为yield表达式的值——next的参数‘next’
console.log(l.next('next')) // {value: undefined, done: true}yield表达式的值——undefined

5.案例:抽奖

ES5

function draw (first = 1, second = 3, third = 5) {
  let firstPrize = ['1A', '1B', '1C', '1D', '1E']
  let secondPrize = ['2A', '2B', '2C', '2D', '2E', '2F', '2G', '2H', '2I', '2J']
  let thirdPrize = ['3A', '3B', '3C', '3D', '3E', '3F', '3G', '3H', '3I', '3J', '3K', '3L', '3M', '3N', '3O', '3P']
  let result = []
  let random
  // 抽一等奖
  for (let i = 0; i < first; i++) {
    random = Math.floor(Math.random() * firstPrize.length)
    // 使用concat合并数组,使用splice删除数组中选中的元素并返回被删除的元素合并到result数组中
    result = result.concat(firstPrize.splice(random, 1))
  }
  // 抽二等奖
  for (let i = 0; i < second; i++) {
    random = Math.floor(Math.random() * secondPrize.length)
    // 使用concat合并数组,使用splice删除数组中选中的元素并返回被删除的元素合并到result数组中
    result = result.concat(secondPrize.splice(random, 1))
  }
  // 抽三等奖
  for (let i = 0; i < third; i++) {
    random = Math.floor(Math.random() * thirdPrize.length)
    // 使用concat合并数组,使用splice删除数组中选中的元素并返回被删除的元素合并到result数组中
    result = result.concat(thirdPrize.splice(random, 1))
  }
  return result
}

let t = draw()
for (let value of t) {
  console.log(value)
}

ES6

function * draw (first = 1, second = 3, third = 5) {
  let firstPrize = ['1A', '1B', '1C', '1D', '1E']
  let secondPrize = ['2A', '2B', '2C', '2D', '2E', '2F', '2G', '2H', '2I', '2J']
  let thirdPrize = ['3A', '3B', '3C', '3D', '3E', '3F', '3G', '3H', '3I', '3J', '3K', '3L', '3M', '3N', '3O', '3P']
  let count = 0 // 控制抽奖人数
  let random
  while (1) {
    if (count < first) {
      random = Math.floor(Math.random() * firstPrize.length)
      yield firstPrize[random] // 被抽中的人选
      count++
      firstPrize.splice(random, 1) // 去掉被抽中的人,防止重复
    } else if (count < first + second) {
      random = Math.floor(Math.random() * secondPrize.length)
      yield secondPrize[random] // 被抽中的人选
      count++
      secondPrize.splice(random, 1) // 去掉被抽中的人,防止重复
    } else if(count < first + second + third) {
      random = Math.floor(Math.random() * thirdPrize.length)
      yield thirdPrize[random] // 被抽中的人选
      count++
      thirdPrize.splice(random, 1) // 去掉被抽中的人,防止重复
    } else {
      console.log('本轮抽奖结束')
      return false
    }
  }
}

let t = draw()
console.log('下面输出一等奖名单:')
console.log(t.next().value)
console.log('下面输出二等奖名单:')
console.log(t.next().value)
console.log(t.next().value)
console.log(t.next().value)
console.log('下面输出三等奖名单:')
console.log(t.next().value)
console.log(t.next().value)
console.log(t.next().value)
console.log(t.next().value)
console.log(t.next().value)
console.log(t.next().value)

6.案例:用Generator实现一个斐波那契数列

function * f () {
  let sum1 = 0
  let sum2 = 1
  yield sum1
  yield sum2
  while (1) {
    yield sum1 = sum1 + sum2;
    [sum1, sum2] = [sum2, sum1] // sum1 = [sum2, sum2 = sum1][0] // 交换
  }
}

let l = f()
for (let i = 0; i < 12; i++) {
  console.log(l.next().value)
}

拓展: