JavaScript 言語には、Array、String、Date をはじめとする組み込みオブジェクトがいくつかあります。しかしカスタム関数を作成したい場合には、用意されたメソッドの 1 つを使って独自のカスタム・オブジェクトを作成することができます。JavaScript 言語を使って独自のカスタム・オブジェクトを作成することには多くのメリットがあり、例えば、それらのカスタム・オブジェクトをそのまま複数のプロジェクトで容易に再利用することができます。またカスタム・オブジェクトによって、JavaScript 言語に初めから用意されているオブジェクトにはない機能を備えた関数を利用できるようになります。他のカスタム・オブジェクトと組み合わせてライブラリーを作成し、そのライブラリーを他の Web 開発者に配布することもできます。
オブジェクトはプロパティーとメソッドによって実用的なものになります。オブジェクトの概念を理解する最も容易な方法は、実際のオブジェクトを考えてみることです。そこで、オブジェクトの例として犬について考えてみましょう。犬には、足、耳、尾、場合によっては色などのプロパティーがあります。また犬には、吠える、食べる、眠る、等々のメソッドがあります。メソッドを使用することで、犬のプロパティーを変更することができます。例えば、犬が吠えているときには耳が立っているかもしれません。一方で犬が眠っているときには耳がだらりとしているかもしれません (もちろん、グレートデーンの場合は別です)。皆さんのプロジェクトで犬オブジェクトを使いたいとします。複数の犬オブジェクトを作成したい場合、すべての犬オブジェクトが持つ基本プロパティーと基本メソッドの数々はどれも同じなので、犬オブジェクトを使用するとプロジェクトの時間を大きく節約することができます。また、別のプロジェクトで犬オブジェクトを使用したい場合には、既に作成したオブジェクトを容易に再利用することができます。
JavaScript 言語を使ってカスタム・オブジェクトを作成する方法には、以下の方法があります。
Object関数を使用する方法- リテラル表記を使用する方法
- オブジェクト・コンストラクターとプロトタイプを使用する方法
この記事では、単純なフォト・ギャラリー・オブジェクトを実際に作成する例を用いて、上記 3 つの方法をすべて説明します。
この記事を読み進めるには JavaScript 言語の基礎知識が必要です。サンプルを理解するためには、「ダウンロード」セクションからサンプル・コードをダウンロードしてください。JavaScript 言語の基礎をもっと学びたい場合には、「参考文献」に挙げた記事を参照してください。
JavaScript 言語を使用してオブジェクトを作成するための最も容易な方法の 1 つが Object 関数を使用する方法です。JavaScript 言語には Object という名前の関数が含まれており、この関数と new 演算子を使用すると、オブジェクトを作成することができます。オブジェクトを作成することによってカスタム機能を実現したい場合、その機能がどのようなものであれ、Object 関数が出発点となります。new 演算子と Object 関数を使用して作成されたオブジェクトを参照するためには、単純にそのオブジェクトに変数名を割り当てます (リスト 1)。
リスト 1.
Object 関数を使ってカスタム・オブジェクトを作成するvar Gallery = new Object(); |
Gallery オブジェクトを実用的なものにするためには、機能を実現するためのプロパティーとメソッドを Gallery オブジェクトに追加します。リスト 2 には、Gallery オブジェクトに追加された 3 つのプロパティーと 3 つのメソッドが含まれています。
リスト 2. プロパティーとメソッドを持つカスタム
Gallery オブジェクト
var Gallery = new Object();
window.onload= function()
{
Gallery.Images = ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'];
Gallery.CurrentIndex = 0;
Gallery._loopInterval = setInterval(Gallery.Next, 2500);
};
Gallery.Next = function()
{
if(Gallery.CurrentIndex < (Gallery.Images.length-1))
{
Gallery.CurrentIndex++;
}
else
{
Gallery.CurrentIndex = 0;
}
Gallery.Display();
};
Gallery.Prev = function()
{
if(Gallery.CurrentIndex > 0)
{
Gallery.CurrentIndex--;
}
else
{
Gallery.CurrentIndex = (Gallery.Images.length-1);
}
Gallery.Display();
};
Gallery.Display = function()
{
var photoGallery = document.getElementById('photo-gallery');
var currentImage = Gallery.Images[Gallery.CurrentIndex];
photoGallery.src = "../assets/img/"+currentImage;
};
|
Gallery オブジェクトのプロパティーは、CurrentIndex、Images、_loopInterval です。これらを Gallery オブジェクトのプロパティーとして定義するためには、ドット構文を使用してこれらのプロパティーを Gallery オブジェクトに単純に割り当てます。つまりドットと変数名を追加し、その変数に値を割り当てます。リスト 2 で使用しているメソッドは、Next、Prev、Display です。これらを Gallery オブジェクトのメソッドとして定義するためには、ドット構文を使用して各メソッドに独自の関数を割り当てます。
Next メソッドと Prev メソッドはどちらも、Gallery オブジェクトのプロパティーを使用しています。CurrentIndex プロパティーは Images 配列の現在のインデックスが何であるかを明らかにするので、インデックスの値をインクリメントまたはデクリメントすると、CurrentIndex プロパティーは配列内の異なる要素を参照します。Images プロパティーはギャラリーに表示する画像を格納するための配列です。_loopInterval プロパティーはループ処理によってギャラリーの各画像を自動的に 2.5 秒ずつ表示するように設定されています。
Gallery オブジェクトの Next メソッドと Prev メソッドは似ています。Next メソッドは Images 配列の現在のインデックス値をインクリメントし、Prev メソッドは現在のインデックス値をデクリメントします。そのため、Display メソッドが呼び出されるたびに、異なる写真が表示されます。
Gallery オブジェクトのいずれかのメソッド (例えば Next メソッド) を呼び出すためには、単純に Gallery オブジェクトを参照してドットを続け、その後にメソッドの名前 (Next)、そして最後に開き括弧と閉じ括弧を続けます (リスト 3)。
リスト 3. カスタムの
Gallery オブジェクトの Next メソッドを呼び出すGallery.Next(); |
このオブジェクトを実際に動作させるために、Images 配列の画像をナビゲートするコントロールを簡単に作成することができます。まず、JavaScript ファイルを含める必要があります。この場合、その JavaScript ファイルは Gallery.js という外部ファイルです。そして、画像を表示するための HTML の img タグを追加し、「Next (次へ)」と「Previous (前へ)」のナビゲーションを制御するハイパーリンクを追加すればよいのです (リスト 4)。
リスト 4. カスタムの
Gallery オブジェクトと Gallery 関数を含む HTML ファイルの例
<html>
<head>
<title>Getting Started with Object-Oriented JavaScript</title>
<script type="text/javascript" src="js/Gallery.js"></script>
</head>
<body>
<img src="../assets/img/istockphoto_14149033.jpg" id="photo-gallery" />
<p>
<a href="#" onclick="Gallery.Prev();">< Previous</a>
<a href="#" onclick="Gallery.Next();">Next ></a>
</p>
</body>
</html>
|
JavaScript 言語でオブジェクトを作成するための、もう 1 つの方法が、リテラル表記を使用する方法です。この方法は JavaScript 1.2 以降でサポートされています。リテラル表記には、Object 関数によって作成されるオブジェクトの場合とまったく同じように、プロパティーとメソッドを含めることができます。
リテラル表記を使ってカスタム JavaScript オブジェクトを作成する方法は、他のプログラミング言語で連想配列を作成する方法と似ています。リテラル表記を使ってオブジェクトを作成するためには、単に開き波括弧とそれに続く閉じ波括弧を変数に割り当てます (リスト 5)。
リスト 5. リテラル表記を使ってカスタム・オブジェクトを作成する
var Gallery = {};
|
リテラル表記を使って作成されたオブジェクト内にプロパティーを定義するためには、変数名と変数の値の間にコロンを使用し、すべてのプロパティーをカンマで区切る必要があります (リスト 6)。
リスト 6. リテラル表記を使ってカスタム・オブジェクトにプロパティーを追加する
var Gallery = {
Images: ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'],
CurrentIndex: 0
};
|
リテラル表記を使って作成されたオブジェクト内にメソッドを定義する方法は、プロパティーを定義する方法と似ています。メソッドを作成するためには、まず変数名を宣言し、その後にコロン、そして関数を続けます。オブジェクト内に複数のメソッドを定義するためには、各メソッドをカンマで区切る必要があります (リスト 7)。
リスト 7. リテラル表記を使ってカスタム・オブジェクトにメソッドを追加する
var Gallery = {
Images: ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'],
CurrentIndex: 0,
Next: function()
{
if(Gallery.CurrentIndex < (Gallery.Images.length-1))
{
Gallery.CurrentIndex++;
}
else
{
Gallery.CurrentIndex = 0;
}
Gallery.Display();
}
};
|
Object 関数を使う場合とリテラル表記を使う場合で異なる点として、リテラル表記ではプロパティーとメソッドを定義する場合に各プロパティーとメソッドの前にオブジェクトの名前を指定する必要がないことも挙げられます。リスト 8 はリテラル表記を使用した Gallery オブジェクトの完全な例を示しています。
リスト 8. リテラル表記を使用したカスタムの
Gallery オブジェクト
var Gallery = {
Images: ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'],
CurrentIndex: 0,
Next: function()
{
if(Gallery.CurrentIndex < (Gallery.Images.length-1))
{
Gallery.CurrentIndex++;
}
else
{
Gallery.CurrentIndex = 0;
}
Gallery.Display();
},
Prev: function()
{
if(Gallery.CurrentIndex > 0)
{
Gallery.CurrentIndex--;
}
else
{
Gallery.CurrentIndex = (Gallery.Images.length-1);
}
Gallery.Display();
},
Display: function()
{
var photoGallery = document.getElementById('photo-gallery');
var currentImage = Gallery.Images[Gallery.CurrentIndex];
photoGallery.src = "../assets/img/"+ currentImage;
}
};
window.onload = function()
{
var _loopInterval = setInterval(Gallery.Next, 2500);
};
|
このオブジェクトを使用するには、このオブジェクトをリスト 4 の HTML ファイルに含めます。それ以外のコードは、関数呼び出しを含め、同じままです。
Object 関数またはリテラル表記を使用するオブジェクトの唯一の欠点として、これらのオブジェクトを何度もインスタンス化することはできません。例えば、この 2 つのタイプのオブジェクトで new 演算子を使用できるのは、そのオブジェクトを最初に作成した時のみです。つまり、そのオブジェクトを再利用して別のインスタンスを作成することはできません。この記事の例で言えば、1 つの HTML ファイルの中で複数のギャラリーを作成したい場合には、JavaScript ファイルを何度も含め、それぞれのギャラリーに異なる名前を付ける必要があります。すると、同じオブジェクトが異なる名前でいくつも重複することになります。従ってそうした場合には、Object 関数またはリテラル表記を使用するオブジェクトは不適切です。一方、1 つのオブジェクトを 1 度のみ使用する場合には、このようなタイプのオブジェクトで問題はありません。何度もインスタンス化できるオブジェクトを作成するためには、オブジェクト・コンストラクターとプロトタイプを使用する必要があります。
複数回インスタンス化できるオブジェクトが必要な場合には、オブジェクト・コンストラクターとプロトタイプを使用してオブジェクトを作成します。オブジェクト・コンストラクターは他のどの関数とも違いはありませんが、関数の名前にはオブジェクトの名前を指定し、その関数の中でオブジェクトを作成します。この記事の例では、オブジェクトの名前は Gallery ですが、Gallery オブジェクトのインスタンスを複数作成できるようにしたいので、ここでは GalleryObj という名前にしました。
オブジェクト・コンストラクターを使用する方法が他の方法と異なるのは、プロパティーとメソッドをオブジェクトに追加する方法です。コンストラクターにメソッドを追加することは、ほぼ間違いなく不適切であるため、私自身はコンストラクターにメソッドを追加することはしませんが、それ自体は可能です。オブジェクト・コンストラクターにプロパティーまたはメソッドを追加するには、プロパティーまたはメソッドの名前の前に this キーワードを使用し、それらの名前をオブジェクト自体に割り当てます (リスト 9)。
リスト 9. オブジェクト・コンストラクターのプロパティーを定義する
function GalleryObj()
{
this.Images = ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'];
this.CurrentIndex = 0;
this._loopInterval = setInterval(this.Next, 2500);
}
|
私が好んで使用するのは、オブジェクト・コンストラクターにメソッドを追加する方法ではなく、prototype キーワードを使用する方法です。prototype キーワードにより、JavaScript 言語で継承を実現することができます。例えば、オブジェクト・コンストラクターを使用してオブジェクトを定義した後、そのオブジェクトにメソッドを継承させたい場合には、prototype キーワードを使用します。つまり prototype キーワードを使用することにより、オブジェクトにメソッドを追加すること、そしてそのオブジェクトのすべてのインスタンスで、そのメソッドを使用することが可能になります (リスト 10)。
リスト 10.
prototype キーワードを使ってオブジェクトにメソッドを追加する
GalleryObj.prototype.Next = function()
{
if(Gallery.CurrentIndex < (Gallery.Images.length-1))
{
Gallery.CurrentIndex++;
}
else
{
Gallery.CurrentIndex = 0;
}
Gallery.Display();
};
|
リスト 11 は、コンストラクター関数とプロトタイプを使用した Gallery オブジェクトの例の全体を示しています。
リスト 11. オブジェクト・コンストラクターとプロトタイプを使用したカスタムの
GalleryObj オブジェクト
function GalleryObj()
{
this.Images = ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'];
this.CurrentIndex = 0;
this._loopInterval = setInterval(this.Next, 2500);
}
GalleryObj.prototype.Next = function()
{
if(Gallery.CurrentIndex < (Gallery.Images.length-1))
{
Gallery.CurrentIndex++;
}
else
{
Gallery.CurrentIndex = 0;
}
Gallery.Display();
};
GalleryObj.prototype.Prev = function()
{
if(Gallery.CurrentIndex > 0)
{
Gallery.CurrentIndex--;
}
else
{
Gallery.CurrentIndex = (Gallery.Images.length-1);
}
Gallery.Display();
};
GalleryObj.prototype.Display = function()
{
var photoGallery = document.getElementById('photo-gallery');
var currentImage = Gallery.Images[Gallery.CurrentIndex];
photoGallery.src = "../assets/img/"+ currentImage;
};
var Gallery = new GalleryObj();
|
ここでは同じ HTML ファイルを使用するために、オブジェクトの名前を GalleryObj にしました。こうすることで、このオブジェクトをインスタンス化する際には、そのインスタンスの名前を Gallery にすることができます。また、今度はギャラリーの写真を自動的に進める間隔をインスタンスごとに定義しており、オブジェクトの定義の中で定義しているわけではありません。こうすることで、各ギャラリーのインスタンスの間隔を別々に制御することができます。
ここで、GalleryObj オブジェクトの別のインスタンスを作成したい場合には、単純に新しいインスタンスを定義します (リスト 12)。
リスト 12. カスタムの
GalleryObj オブジェクトの別のインスタンスを作成するvar Gallery2 = new GalleryObj(); |
これを見るとわかるように、オブジェクト・コンストラクターは非常に強力であり、作成できるオブジェクトのインスタンスの数に限りはありません。またプロトタイプを使用する方法も強力で、即座にメソッドを追加することができ、そのオブジェクトのすべてのインスタンスから、追加されたメソッドにアクセスすることができます。
JavaScript のコア・オブジェクトのプロトタイプを使用する
これでプロトタイプを使用する方法について理解できたので、JavaScript のコア・オブジェクトにカスタム・メソッドを追加する方法について調べてみましょう。場合によると、追加機能が必要でありながら、必ずしもカスタム・オブジェクトが必要ない場合があります。例えば、ギャラリーの Images 配列の特定項目のインデックスを取得する必要があるとします。そうした場合、再利用できないランダムな関数を作成する代わりに、Array オブジェクトを継承することができます。そのためには prototype キーワードを使用して Array オブジェクトに新しいメソッドを追加します (リスト 13)。
リスト 13.
prototype キーワードを使用し、JavaScript 言語のコア・オブジェクト Array に新しいメソッドを追加する
Array.prototype.GetIndex = function(item)
{
for(var i=0; i<this.length; i++)
{
if(this[i] == item)
{
return i;
}
}
}
|
Array オブジェクトに追加した新しいメソッドを使用するためには、作成された任意の配列から、他の任意の関数を呼び出す場合と同様に、その新しいメソッドを単純に呼び出します。リスト 14 には Images 配列が含まれており、この配列は配列内の特定の画像のインデックスを取得するための GetIndex を呼び出しています。
リスト 14.
prototype キーワードを使用し、コア・オブジェクト Array にメソッドを追加する
<html>
<head>
<title>Getting Started with Object-Oriented JavaScript</title>
<script type="text/javascript" src="js/Array.js"></script>
<script type="text/javascript">
var Images = ['istockphoto_14149033.jpg', 'istockphoto_14232771.jpg',
'istockphoto_14667148.jpg'];
var index = Images.GetIndex('istockphoto_14232771.jpg');
alert("Index: "+ index);
</script>
</head>
<body>
</body>
</html>
|
JavaScript 言語のコア・オブジェクトを継承すると、既存のオブジェクトに機能を追加することができます。非常に驚くべきことですが、Array オブジェクトに対して Array オブジェクト以上のことを実行するように指示することができ、その拡張された機能を任意のプロジェクトで再利用することができるのです。
この記事で紹介した方法は、カスタム・オブジェクトを作成する方法として、それぞれに独自のやり方で有効です。Object 関数による方法とリテラル表記による方法は似ており、どちらを使用するかの選択は完全に開発者の好み次第です。どちらの方法も、何度もインスタンス化する必要のないオブジェクトを作成する場合には適切な選択肢です。何度もインスタンス化する必要のあるオブジェクトを作成する場合には、オブジェクト・コンストラクターとプロトタイプを使用する方法が理想的です。
JavaScript 言語でカスタム・オブジェクトを作成すると、シンプルかつ整然としたコードを保ったまま、極めて複雑な機能を実現することができます。この記事を読んで、皆さんの JavaScript プロジェクトでカスタム・オブジェクトを使用し、ある目的で複雑な対話動作を実現してみる気になったようであれば幸いです。
| 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|---|---|---|
| Sample code for this article | oojs.zip | 197KB | HTTP |
学ぶために
- 「JavaScript 言語入門」(2011年4月) を読み、JavaScript 言語の基本を理解してください。
- 「JavaScript and the Document Object Model」(developerWorks、2002年7月) を読んでください。JavaScript によって DOM を処理する方法を解説し、またユーザーがメモを追加でき、メモの内容を編集できる Web ページの作成方法を解説しています。
- 「境界を越える: JavaScript の言語機能」(developerWorks、2006年12月) を読み、JavaScript の機能を探ってください。
- DevGuru は JavaScript 言語に対する包括的なガイドです。
- Douglas Crockford 氏による「"Classical Inheritance in JavaScript」をよく読み、JavaScript 言語について学んでください。
- developerWorks の Web development ゾーンには、Web ベースの多様なソリューションを解説した記事が豊富に用意されています。
製品や技術を入手するために
- JavaScript 言語の基礎を理解できたら、JavaScript 言語を使用した開発のスピードを高めるための手段として、jQuery ライブラリーが有効です。
- 皆さんの目的に最適な方法で IBM 製品を評価してください。製品の試用版をダウンロードする方法、オンラインで製品を試す方法、クラウド環境で製品を使う方法、あるいは SOA Sandbox で数時間を費やし、サービス指向アーキテクチャーの効率的な実装方法を学ぶ方法などがあります。
議論するために
- 今すぐ developerWorks プロフィールを作成し、JavaScript に関する ウォッチ・リストを設定してください。developerWorks コミュニティーとずっとつながっていられます。
- Web 開発に関心を持つ他の developerWorks メンバーを見つけてください。
- Web の話題に焦点を絞った developerWorks のグループの 1 つに参加し、皆さんの知識を共有してください。
- Roland Barcia が彼のブログの中で Web 2.0 とミドルウェアについて語っています。
- developerWorks のメンバーが Web のトピックに関して共有するブックマークを調べてみてください。
- 即座に答えを得るために、Web 2.0 Apps フォーラムを訪れてください。
- 即座に答えを得るために、Ajax フォーラムを訪れてください。

Kris Hadlock は、1996年から契約 Web 開発者および設計者として、SPIN Magazine、IKEA、United Airlines、JP Morgan Chase、GoDaddy Software、Fire Mountain Gems などの企業のプロジェクトを手掛けてきました。著書には『Ajax for Web Application Developers』(Sams)、『The ActionScript Migration Guide』(New Riders) があります。また、コラムニストおよびライターとしても、Peachpit.com、InformIT.com、Practical Web Design magazine などの数々の Web サイトや設計関連の雑誌で活躍しています。彼は、フォームと関数の融合を専門とする Web 設計およびソフトウェア開発会社、www.studiosedition.com の創始者でもあります。