前回までで、基本的なデータ型を拡張したメソッドを紹介してきた。今回からは、JavaScriptによる処理に関する拡張メソッドを紹介していこう。まずは配列、関数、イベントだ。説明に用いるPrototype.jsのバージョンは、本年1月にリリースされた1.6.0.2とする。

ただしメソッドの数が多く本稿ではその一部しか紹介できない。詳細はAPIリファレンスなどを参照していただきたい。また、省略可能な記述は[~]で表す。


配列(Array)のメソッド

Arrayに対する拡張メソッドは、それ自身のものだけでなく、要素の集合に対する操作を便利に行うEnumerableのメソッドも含むため、拡張メソッドの数が特に多い。そのためここでは、メソッド名だけでは、そのはたらきが分かりにくいものについて利用例を示す。

配列.compact() nullでない要素のみの配列を生成。

['a', null, 'b', null, 'c'].compact();  // ['a', 'b', 'c']

配列.flatten() 多次元配列から1次元配列にする。

[0, 1, ['a', 'b'], 2, ['c']].flatten(); // [0, 1, 'a', 'b', 2, 'c']

配列1.intersect( 配列2 ) 配列1, 配列2に共通した要素を持つ配列を生成。

[1, 2, 3].intersect( [2, 3, 4] );       // [2, 3]

配列.reduce() 要素が1つだけなら要素のみ、要素が複数のときは配列自身を戻り値とする。

typeof [1].reduce();  // 'number'
var a = [1, 2];  ( a.reduce() == a ); // true

配列.toJSON() JSON形式の文字列を生成。

[{ name : 'a', desc : 'リンク'}, { name : 'p', desc : '段落' }].toJSON();
// [{"name": "a", "desc": "リンク"}, {"name": "p", "desc": "段落"}]

関数(Function)のメソッド


関数.bind( [ 処理中でthisとなるオブジェクト [, 引数, ... ]] );
関数を実行するときに第1引数のオブジェクトをthisとし、続く引数も関数に渡す。

function sum()  {
  var t = 0;
  var a = $A( arguments );    // [3, 4, 5]    bind()の第2引数とb()の引数
  var c = this.concat( a );   // [1, 2, 3, 4, 5]   thisは[1, 2]
  return c.inject( 0, function( s, n )  {  return s + n;  } );
}
var b = sum.bind( [1, 2], 3 );
b( 4, 5 );  // 15

関数.bindAsEventListener( [ 処理中でthisとなるオブジェクト [, 引数, ... ]] );
bind()の第2引数にイベントオブジェクトを自動的に追加するもので、イベントハンドラに対して実行される。

function eh( ev )  {    // イベントハンドラ
  this.removeChild( this.firstChild );    // thisはボタンの要素
  this.appendChild( document.createTextNode( arguments[1] ) );   // ボタンのテキストを書き換え
}
$( 'left' ).observe( 'click', eh.bindAsEventListener( $( 'right' ), '左がクリックされた' ) );
$( 'right' ).observe( 'click', eh.bindAsEventListener( $( 'left' ), '右がクリックされた' ) );

[対象となる要素]
<button id="left">左ボタン</button>
<button id="right">右ボタン</button>

図1 左ボタンをクリックしたとき

図2 右ボタンをクリックしたとき


関数.delay( 秒数 [, 引数, ... ] );
関数を秒数だけ待ってから実行する。関数の記述方法に注意。

$( 'left' ).hide();  →  Element.hide.delay( 3, 'left' );  // 3秒後に実行

イベント(Event)のメソッド


Event.observe( 要素のIDもしくはDOMオブジェクト [, イベント名[, イベントハンドラ]] );
  または
$( 要素のIDもしくはDOMオブジェクト ).observe( [イベント名 [, イベントハンドラ]] );

要素に対してイベントが発生したときに行う処理(イベントハンドラ)を登録する(※documentに対しても拡張済み)。

function eh( ev )  {  alert( '左がクリックされた!' );  }
Event.observe( 'left', 'click', eh );

Event.stopObserving( 要素のIDもしくはDOMオブジェクト [, イベント名 [, イベントハンドラ]] );
  または
$( 要素のIDもしくはDOMオブジェクト ).stopObserving( [イベント名 [, イベントハンドラ]] );

登録していたイベント処理を削除する(※documentに対しても拡張済み)。

Event.stopObserving( 'left', 'click', eh );

イベントオブジェクト.element();                    // イベントが発生した要素
イベントオブジェクト.findElement( CSSセレクタ ); // 1.5までの引数はタグ名

イベントが起きた要素の検出。イベントが起きた要素に対して何かの処理を行うときには、上記のメソッドでそれを検出できる。element()はtargetがテキストのときはその親要素が戻り値となる。findElement()は1.6から引数にCSSセレクタを記述できるようになった。


イベントオブジェクト.isLeftClick();    // 左ボタン
イベントオブジェクト.isMiddleClick();  // 中ボタン
イベントオブジェクト.isRightClick();   // 右ボタン

クリックされたマウスのボタンを特定。執筆時現在のAPIドキュメントには isLeftClick() のみが掲載されているが、ソースコード上は他の2つも定義されている。3ボタンマウスのユーザーは相対的に少ないと見られることや、右ボタンのクリックではコンテキストメニューを表示するWebブラウザが多いことから、あまり実用的ではないのかもしれない。


イベントオブジェクト.pointerX();  // X軸(ピクセル)
イベントオブジェクト.pointerY();  // Y軸(ピクセル)
イベントオブジェクト.pointer();   // 戻り値は{ x : X軸, y : Y軸 }

マウスがクリックされた位置の座標を検出。X, Y各軸ごとのpointX() / pointY()と、両軸の分が一括して戻されるpointer()とがあるが、ソースコード上は、前2つが後者から各軸の分のみを取得し、戻り値としている。


イベントオブジェクト.stop();
親要素でのイベント処理をしない。マウスのクリックに対するイベント処理が親子それぞれの要素で登録されているときに、子要素がクリックされると、まず子要素で登録されたイベント処理が実行され、そのあと親要素で登録されたイベント処理が行われる。これをイベントバブルという。

この途中で stop() が実行されると、これより上階層の親要素ではイベント処理が実行されなくなる。そのため、stop()によってイベントが有効な範囲を制御することができる。

今回紹介したメソッドの中には、実行されるWebブラウザの種類に応じて書き分けなければならなかった処理が多く含まれている。Prototype.jsによって、そうした不便が少しでも解消されることを筆者は願っている。