はじめに
Prototypeのホームページには、「Prototypeは動的なWebアプリケーションの開発を簡易化することを目的としたJavaScriptフレームワークである」と書かれています。Prototypeは、クラス主導の開発や継承など多くのオブジェクト指向の手法を使ってJavaScriptアプリケーションを開発できるようにすることで、その目的を完全に果たしています。事実、このフレームワークには役に立つ機能が数多く用意されており、一度使い始めたら、どのアプリケーションの開発にも利用したくなります。
Prototypeの最大の特徴は、その機能豊富なAJAX(Asynchronous JavaScript and XML)ライブラリにあり、これによって、JavaScriptを介してサーバの非ブロック呼び出しを行うという人気のWeb開発手法を簡単に取り入れることができます(昨年度のAjaxian.com 2006 Surveyでは、Prototypeは最も人気の高いAJAXフレームワークという評価を受けました)。もちろん、Prototypeで実現できることはすべて、Prototypeのベースである普通のJavaScriptでも実現できます。しかし、わざわざ仕事を増やす必要はありません。例えば、同じタスクを行うのにdocument.getElementById("myElement")
と$("myElement")
のどちらを使いたいですか? 本稿では、$("myElement")
を選んだ読者のために、$
をはじめとする役に立つPrototype
関数を詳しく説明します。
とはいえ、Prototypeは巨大なフレームワークなので、1回では説明しきれません。そこで、ここではごく一部の重要な機能だけを紹介します。フレームワーク全体を深く理解するには、ソースコードを見てください。基本な仕組みを知るにはソースコードを見るのが一番であり、必要に合わせて修正を加えることもできます。
便利な関数
WebアプリケーションでPrototypeを使うには、まず最新のバージョンをダウンロードします(本稿執筆時の最新バージョンは1.4.0)。実際に必要なファイルは「prototype.js」だけで、次のように<script>
タグを使ってページにインクルードします。
<script type="text/javascript" src="yourPath/prototype.js"></script>
先ほど取り上げた$
関数は、document.getElementById
のショートカットです。$
には複数の要素IDを渡すこともできます。次のコードを実行すると、要求された要素を含む配列が返されます。
<!-- HTML --> <div id="firstElem">First element's content</div> <div id="secondElem">Second element's content</div> // JavaScript var elems = $("firstElem", "secondElem"); alert(elems[1].innerHTML); //displays "Second element's content"
もう1つの実に役に立つショートカット関数は、フォームフィールドIDを取得してフィールド値を返す$F
です。
<!-- HTML --> <select name="language" id="language"> <option value="JS" selected="selected">JavaScript</option> <option value="Java">Java</option> <option value="C#">C#</option> <option value="Ruby">Ruby</option> </select> // JavaScript var langValue = $F("language"); alert(langValue); //displays "JS"
オブジェクト指向(Object-Oriented:OO)のJavaScript
Prototypeでは、OOスタイルに非常によく似たJavaScriptコードを作成することもできます。例えば、次のクラス定義を見てみましょう。
// Class definition var Person = Class.create(); // Class methods Person.prototype = { //Constructor initialize : function(firstName, lastName, age) { this.firstName = firstName; this.lastName = lastName; this.age = age; }, //method #1 toString : function() { return this.firstName + " " + this.lastName + ", " + this.age; }, //method #2 displayFirstName : function() { alert(this.firstName); } }; var myPerson = new Person("Alessandro", "Lacava", 30); alert(myPerson.toString()); //displays "Alessandro Lacava, 30"
見ての通り、コンストラクタは(慣例により)initialize
メソッドを使って定義されています。さらに、この例では他にtoString
とdisplayFirstName
の2つのメソッドも定義されています。もちろん、メソッドは必要な数だけ定義できます。
また、Prototypeでは、Object.extend
メソッドによって既存のクラスを拡張することもできます。このメソッドは、あるオブジェクトのプロパティとメソッドを別のオブジェクトにコピーします。構文はObject.extend(destination, source)
です。ここでdestination
にはsource
のプロパティとメソッドで拡張するオブジェクトを指定します。
「this」の参照先が期待どおりではない場合
既にご存知のように、JavaScriptの関数は本格的なオブジェクトです。PrototypeはJavaScriptのFunction
クラスにさらに2つの素晴らしいメソッドbind
とbindAsEventListener
を追加します。この2つのメソッドは、イベントハンドラの働きを設定するときに非常に役に立ちます。これらのメソッドの利点をよく理解するために、次のコードを見てみましょう。このコードでは、Person
オブジェクトを作成し、そのdisplayFirstName
メソッドを<div>
のクリックイベントのイベントリスナとして設定します。
<!-- HTML --> <div id="elem">Click Here</div> // JavaScript var person = new Person("John", "Brown", 20); $("elem").onclick = person.displayFirstName;
ここでの目的は、ユーザーが「Click Here」をクリックしたときにファーストネーム(John)を表示することです。しかし、クリックしてみても、undefinedが表示されてしまいます。なぜかと言うと、$("elem").onclick = person.displayFirstName
というコードは、「<div>
のonclick
関数の本体をperson.displayFirstName
関数の本体で置き換える」、つまりalert(this.firstName);
に置き換えることを事実上意味しているからです。
問題は、onclick
が呼び出されたときに、this
キーワードがもはやPerson
を参照していないことです。this
が参照するのは、firstName
プロパティを持っていない<div>
要素です。Prototypeでは、bind
メソッドを次のように利用してこの問題を見事に解決できます。
$("elem").onclick = person.displayFirstName.bind(person);
これで、this
キーワードはPerson
クラスを参照するようになります。このコード行を言葉で表現するなら、「<div>
のonclick
の本体をperson.displayFirstName
の本体で置き換え、かつ、this
キーワードとperson
オブジェクトをbind
でバインドする」となります。bindAsEventListener
関数は同じことを実行するだけでなく、クロスブラウザ方式で呼び出された関数にevent
オブジェクトを渡します。