@okayuの大して技術的ではないブログ

はじめに

JavaScriptでFizzBuzzします。ただ普通にやっても面白くないのでジェネレータを使ってみたいと思います。

  1. ジェネレータってなんだよ
    • ES2015で追加されたJavaScriptの比較的新しい機能です
  2. 何をジェネレートすんだよ
    • 反復可能オブジェクトをジェネレートします
  3. 反復ってなんだよ
    • for-of
    • スプレッド構文(...iterator)
    • 分割代入(const [hoge, huga] = iterator;)
    • とかです。多分
  4. 配列じゃだめなの?
    • 無限を扱えます
    • 無限FizzBuzzとか無限フィボナッチ数列とか無限素数とかいろいろできます

FizzBuzz!

/**  
 * @param {number} max  
 */  
function* fizzbuzzGen(max = Infinity) {  
  for (let i = 1; i <= max; i++) {  
    yield (  
      i % (5 * 3) === 0 ? 'FizzBuzz' :  
      i % 5 === 0 ? 'Buzz' :  
      i % 3 === 0 ? 'Fizz' :  
      i.toString()  
    );  
  }  
}  

for (const fizzbuzz of fizzbuzzGen(10000)) {  
  console.log(fizzbuzz);  
}  

fizzbuzzGen()に渡す数のぶんループして出力します。つまり10000回console.logします。

解説

MDNに譲ります。

私自身あんまり詳しくないですが簡単に説明すると…

  • 反復可能オブジェクト === [Symbol.iterator]()メソッドとしてイテレータを持つオブジェクト
    • StringArrayMapSet[Symbol.iterator]()メソッドを持つ反復可能オブジェクト
      • [][Symbol.iterator][].values()を返す
    • [Symbol.iterator]()メソッドを作れば自作classとかもイテラブルになる(なった)
  • イテレータ === next()メソッドを持ったオブジェクト
    • next()メソッドではイテレータリザルトを返す
    • for-ofは自動でうまい具合にnext()メソッドを呼び出しているだけ(多分)
  • イテレータリザルト === { value: 値, done: false }{ done: true }のこと
    • これを目印にfor-ofなどはうまいことやってるっぽい
  • カスタムイテレータ === 一から自作したイテレータ
    • イテレータリザルトを自力で管理する
    • とってもめんどくさい => 下手するとバグる
  • ジェネレータ === イテレータをジェネレートする特殊な関数
    • yield神!
    • とっても簡単 => 安全
  • yield value === ジェネレータ版return value
    • その値(value)を返して処理を一時停止する
    • next()メソッドが呼ばれると処理を再開し、次のyieldまで実行する
  • yield* values === 他の反復可能オブジェクト(values)を呼び出すやつ
    • 与えられた反復可能オブジェクトの値を一つ一つ取り出して、全てに対しyieldを行う
    • yield 1; yield 2; yield 3; === yield* [1, 2, 3];(多分)

おわりに

思えば、letconst、アロー関数やclass、テンプレート文字列やPromise、そしてこのイテレータ関連のfor-ofやスプレッド構文やSymbolなどなど…ES2015って結構やばいやつだったんですね…。

この記事へのコメント

まだコメントはありません