Prototype & script.aculo.us 4章まとめ 1
Prototype & script.aculo.us を買った。なかなか面白いなー。
4章の「Enumerable で高度なコレクション」の自分用メモとして書いておく。
残りの続きはまた書こう。
Prototype & script.aculo.us ―JavaScriptライブラリによるAjaxアプリケーション開発
- 作者: Christophe Porteneuve,栗山淳(監訳),吉田遼二
- 出版社/メーカー: オライリージャパン
- 発売日: 2008/07/28
- メディア: 大型本
- 購入: 5人 クリック: 51回
- この商品を含むブログ (35件) を見る
each による反復処理(イテレーション)
Enumerable の心臓部として、反復メソッドの中心となる each() メソッドがある。
each(iterator [, context] ) -> enumerable
////prototype.js 1.6.0.2 589行目 var Enumerable = { each: function(iterator, context) { var index = 0; iterator = iterator.bind(context); try { this._each(function(value) { iterator(value, index++); }); } catch (e) { if (e != $break) throw e; } return this; },
$break 列挙を途中で切り上げる
for や while を使った定番のループ処理では、continue と break でループを切り上げることができた。
では、each() を使った時はどうするか?
$break という名前の特別な例外定数を使う。
var result = []; $R(1, 10).each(function(n) { if (0 == n % 2) return; if (n > 6) throw $break; result.push(n); }); // result -> [1,3,5]
$continue は?
もともと反復処理を中断させるために、$break と $continue が用意されていた。
が、後者は return で代用ができるのと、パフォーマンスが優れているため、
Prototype 1.5.1 から追放された。
列挙のコンテキスト
Prototype 1.6 から、すべての Enumerable メソッドに context という引数が新たに追加された。
これは、必要に応じてJavaScript 1.6 以降の動作を真似る目的で導入された、とのこと。
var items = [1,2,3]; items.all(function(item) { console.log(this)}); // Window // this は Window オブジェクトを指し示す var items = [1,2,3]; items.all(function(item) { console.log(this)}.bind(items)); // 1,2,3 // bind してオブジェクトを渡せるが、 var items = [1,2,3]; items.all(function(item) { console.log(this)}, items); // 1,2,3 // こうも渡せるようになった。
使用するメソッドが JavaScript1.6 以降で提供されている場合(メソッドがネイティブな場合)
この引数を使用すると、手作業でイテレータにバインドするのと比べて格段に早くなる。
(ループのたびに、bind() の作成する無名関数によるラッピングのコストを節約できるため)
メソッドの集合
all/every ([ iterator = Prototype.K ]) -> Boolean
any/some ([ iterator = Prototype.K ]) -> Boolean
include/menber(value) -> Boolean
size() -> Number
all/every, any/some, include/menber は別名(エイリアス)。
Prototype.K は特別な関数。働きとしては、最初の引数を受け取り、そのまま何もせずに返す。
all() メソッドも any() メソッドも、反復処理を中断すべき条件に遭遇したら、反復を中止する。
include/member は == ではなく、=== を使用している。
size() メソッドはコレクションの要素数を返す。
var animals = ['cat', 'dog', 'bird']; animals.size(); // 3
要素を見つけることと、フィルタを適用すること
detect/find(iterator) -> firstElement | undefined
filter/findAll/select(iterator) -> Array
grep(pattern [, iterator = Prototype.K] ) -> Array
find/detect() メソッドはイテレータによって、記述される条件にマッチする最初の要素を返す。
条件がマッチする要素がない場合は何も返さないので、結局 undefined を返すことと同じになる。
var str = ['a', 'aa', 'aaa', 'aa', 'a']; console.log( str.find(function(s) { return s.length >= 3; }) ); // aaa console.log( str.find(function(s) { return s.length >= 4; }) ); // undefined //prototype.js 1.6.0.2 640行目 detect: function(iterator, context) { iterator = iterator.bind(context); var result; this.each(function(value, index) { if (iterator(value, index)) { result = value; throw $break; } }); return result; },
filter/findAll/select() メソッドはマッチするすべての要素の配列を返す。
var str = ['a', 'aa', 'aaa', 'aa', 'a']; str.select(function(s) { return s.length >= 2; }) //aa,aaa,aa
grep() メソッドは findAll の特殊なバリエーション。正規表現も使える。
findAll() と同じように、配列要素のうち条件にマッチするものをすべて返す。
また要素そのものではなく、要素を処理した結果の値を使う必要がある場合は、
イテレータを渡すこともできる。
$R(1,30).grep(/[05]$/); //5,10,15,20,25,30 $R(1,30).grep(/[05]$/, function(n) { return n -1; }); //4,9,14,19,24,29