prototype.jsを読み解く

第1回 Prototypeライブラリ(1~197行目)

この記事を読むのに必要な時間:およそ 12 分

はじめに

今回から,Prototypeライブラリについて,中身のコードを読みながら,実装として中で何が行われているのかを見ていこうと思います。

想定している読者は,Prototypeライブラリをただ使うだけでなく,やっていることを理解したいという方,使われているコードを応用して自分なりの改造をしてみたい方,などです。

今回の連載では執筆開始時点の最新版であるバージョン1.5.1.1を対象としています。現在1.6.0rcが準備されていますが,説明の都合上行番号に大きく依存しているため,最後までバージョン1.5.1.1を対象とすることになります。

Prototypeライブラリの構成

名前空間

このライブラリでは,グローバルな名前空間のうち,以下のものを使っています。

名前実体
Prototypeオブジェクト
Classオブジェクト
Abstractオブジェクト
Tryオブジェクト
PeriodicalExecuterPrototypeライブラリ式クラス
TemplatePrototypeライブラリ式クラス
$break空オブジェクト
$continueError形のインスタンス,後方互換性のため
Enumerableオブジェクト
$AArray.from関数オブジェクトの別名
$w関数オブジェクト
Hashコンストラクタとしての関数オブジェクト
$H関数オブジェクト
ObjectRangePrototypeライブラリ式クラス
$R関数オブジェクト
Ajaxオブジェクト
$関数オブジェクト
Elementオブジェクト(元々ブラウザが持っていない場合に作成)
Toggleオブジェクト
Insertionオブジェクト
SelectorPrototypeライブラリ式クラス
$$関数オブジェクト
Formオブジェクト
Fieldオブジェクト。Form.Elementの別名
$F関数オブジェクト。Form.Element.Methods.getValueの別名
Eventオブジェクト(元々ブラウザが持っていない場合に作成)
Positionオブジェクト

他のライブラリや,自分のコードと共存させるときは,これらの名前と衝突しないように気をつける必要があります。同じ名前を使ってしまうと,コードがロードされた順番によって挙動が変わる,というようなわかりにくい問題が発生してしまう場合が出てきます。

オブジェクト,クラスの使われ方

ライブラリ内では,上記の名前空間は大きく分けて以下のような使われ形をしています。

  1. その下に別のオブジェクトを入れるための親名前空間として使う
  2. Class.create()を使って Prototypeライブラリ風のクラスとして定義する
  3. Object.extend()を使って他のクラス,オブジェクトから継承されることを前提とする関数を集める
  4. コードを簡潔に記述する為に短い名前の関数として使う

特に,Object.extend()を使って継承を実現している箇所が多く,最終的にどのオブジェクト・クラスにどのメソッドが定義されているのかがわかりにくい所があります。

コードを追っていく場合は,その名前のオブジェクトの定義部分だけではなく,Object.extend()で拡張されている部分も追っていく必要があります。

既存オブジェクトへの拡張

Prototypeライブラリの特徴の一つとして,既存のオブジェクトへの拡張を行っているというものがあります。

大きくはElementやArray,Stringに対して多数のメソッドを追加していますし,Function,Object,Number,Dateにもいくつかメソッドが追加されています。

これらの追加メソッドは便利なものが多いのですが,副作用に気をつける必要があります。

JavaScriptでコード上でプロパティとして追加されたメソッドには,属性として DontEnum属性を追加することができません。そのため,拡張されたオブジェクトのインスタンスを作成しfor (var i in obj)などでプロパティを列挙すると,他の組み込みメソッドなどとは異なり通常のプロパティとして列挙されるプロパティに含まれるようになってしまいます。

このことを忘れていると,「自分が追加していないプロパティがなぜか含まれている!」ということになり,デバッグに手間取ることになりがちです。

var a = new Array;
a.push(100);
a.push(200);
for (var i in a) {
  console.log(i);
}

というコードでは,配列内の2要素だけが列挙されることを期待したいのですが,Prototypeライブラリをロードした後では,Array.prototypeにメソッドがプロパティとして追加されていますので,0,1というインデックス値のプロパティ以外にも,それらのメソッドが列挙されてしまいます。

この場合は,例えばArrayならfor (var i = 0; i < a.length; i++) { ... }という形で列挙するか,Array.each()などのイテレータメソッドを使う,という形にする必要があります。

先頭のコメント,著作権表示

0001: /*  Prototype JavaScript framework, version 1.5.1.1
0002:  *  (c) 2005-2007 Sam Stephenson
0003:  *
0004:  *  Prototype is freely distributable under the terms of an MIT-style license.
0005:  *  For details, see the Prototype web site: http://www.prototypejs.org/
0006:  *
0007: /*--------------------------------------------------------------------------*/
0008: 

7行目まではコメントです。PrototypeライブラリはMITスタイルのライセンスであることが宣言されています。 このライセンスであるおかげで,商用製品であろうとも利用が可能となっていて,普及が促進されたという側面もあるでしょう。

著者プロフィール

栗山淳(くりやまじゅん)

S2ファクトリー株式会社株式会社イメージソース所属。
本業はWeb制作会社の裏方。得意分野はFreeBSDやPerlのはずだが,必要に迫られるとHTML/CSSやJavaScriptも書く。

コメント

コメントの記入