イテレータの使いどころ (vimperatorのソース読書会?)

ブックマークは溜めるばかりでは意味がないですね。たまには検索をして引き出さないと。
一年半前ほどにつけたブクマで思わぬ拾い物をした。

今現在作っているFirefoxの拡張(textarea/input 要素を vim っぽくする拡張)はvimperatorのソースを参考に作っている(パクっているとも言える)のだけれど、New in JavaScript 1.7 - MDCに書かれているイテレータが良く出てくる。
訳も分からず作っていたわけだけど上二つのページを見つけてやっと理解できてきた。

vimperatorのソースにはクラスとそれを管理するクラスのパターンが3つある。

  • vimperator.Mapクラスとvimperator.Mappingsクラス
  • vimperator.Commandクラスとvimperator.Commandsクラス
  • vimperator.Optionクラスとvimperator.Optionsクラス

管理クラス側のパブリックな場にはadd,getメソッドと__iterator__メソッドが共通してある。
そして、プライベートな場に、オブジェクトを蓄積する配列とイテレータオブジェクトを返す関数がある。

簡略化したソースで示すと

function Class(name){
  this.name = name;
};

fuction ManagerClass(){
  // private
  var array = [];
  function iterator(){
    for (var i=0; i<array.length; i++){
      yield array[i];
    }
    throw StopIteration;
  }
  // public
  var manager = {
    __iterator__: function(){
      return iterator();
    },
    add: function( obj ){
      array.push(obj);
    },
    get: function( name ){
      for (var i=0; i<array.length; i++){
        if ( array[i].name == name ) return array[i];
      }
      return null;
    }
  };
  return manager;
}

な感じになっていて、

var manager = new ManagerClass();
manager.add( new Class('hoge') );
manager.add( new Class('foo') );
manager.add( new Class('bar') );

というふうにオブジェクト化されている。

で、for (var obj in manager)で回すとobjには何が入ってくるかっていうと、add,getメソッドじゃなくて、追加したClassのオブジェクトが入ってくる。add,getメソッドは得られない。半分隠蔽している感じだ。
順を追って書くと、for (var obj in manager)で回すと

  1. managerの中に__iterator__メソッドがあるのでそれが実行される。
  2. __iterator__メソッドはiterator関数を実行する。
  3. iterator関数はyieldがあるのでイテレータオブジェクトを返す。
  4. __iterator__メソッドはイテレータオブジェクトを返す。
  5. めでたくイテレータとして繰り返される

ManagerClassにgetAllみたいなメソッドを定義して

var objs = manager.getAll();
for (var i=0; i<objs.length; i++){
  ....
}

みたいにやるよりスマートなコードが書けるわけだ。

イテレータの初歩かもしれないけれど、僕は感動したのでここに長々と書いてみた。

……というのが、ジェネレータの使いどころなんだと思う。僕は頭が悪いんで、有効に活用できる場合というのを自分ではさーっぱり思いつかないんだけど。なので、せめて、頭のいい人がこの解説みたいな文章を見てyieldの有効な使い道をたくさん考えてくれることを期待します。

Latest topics > JavaScript 1.7のyield文ってなんじゃらほ - outsider reflex

別に僕の頭が良いんじゃなくてvimperatorを作った人が良いんだけれど、これが解にならないかなと1年半前のpiro氏に返信してみる。