【筆記】再學JavaScript ES(6-10)全版本語法——Generator(案例:抽獎&斐波那契數列)


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)
}

拓展:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章