オブジェクト指向の JavaScript コードを作成する

JavaScript 言語を使用してオブジェクトを作成する方法を学ぶ

極めて対話性の高い Web サイトが一般的になった今日では、JavaScript 言語が多用されるようになっています。複雑な JavaScript コードを本格的に作成しようとする場合、カスタム・オブジェクトを作成するためのさまざまな方法と、カスタム・オブジェクトの使い方の基本を理解する必要があります。この記事では、JavaScript 言語を使用してカスタム・オブジェクトを作成するあらゆる方法を説明します。またコード・サンプルを使用しながら、それらのオブジェクトを実際の状況で使用する方法について説明します。

Kris Hadlock, Web Developer/Designer, Studio Sedition

Photo of Kris HadlockKris 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 の創始者でもあります。



2011年 4月 19日

JavaScript 言語には、ArrayStringDate をはじめとする組み込みオブジェクトがいくつかあります。しかしカスタム関数を作成したい場合には、用意されたメソッドの 1 つを使って独自のカスタム・オブジェクトを作成することができます。JavaScript 言語を使って独自のカスタム・オブジェクトを作成することには多くのメリットがあり、例えば、それらのカスタム・オブジェクトをそのまま複数のプロジェクトで容易に再利用することができます。またカスタム・オブジェクトによって、JavaScript 言語に初めから用意されているオブジェクトにはない機能を備えた関数を利用できるようになります。他のカスタム・オブジェクトと組み合わせてライブラリーを作成し、そのライブラリーを他の Web 開発者に配布することもできます。

オブジェクトはプロパティーとメソッドによって実用的なものになります。オブジェクトの概念を理解する最も容易な方法は、実際のオブジェクトを考えてみることです。そこで、オブジェクトの例として犬について考えてみましょう。犬には、足、耳、尾、場合によっては色などのプロパティーがあります。また犬には、吠える、食べる、眠る、等々のメソッドがあります。メソッドを使用することで、犬のプロパティーを変更することができます。例えば、犬が吠えているときには耳が立っているかもしれません。一方で犬が眠っているときには耳がだらりとしているかもしれません (もちろん、グレートデーンの場合は別です)。皆さんのプロジェクトで犬オブジェクトを使いたいとします。複数の犬オブジェクトを作成したい場合、すべての犬オブジェクトが持つ基本プロパティーと基本メソッドの数々はどれも同じなので、犬オブジェクトを使用するとプロジェクトの時間を大きく節約することができます。また、別のプロジェクトで犬オブジェクトを使用したい場合には、既に作成したオブジェクトを容易に再利用することができます。

JavaScript 言語を使ってカスタム・オブジェクトを作成する方法には、以下の方法があります。

  • Object 関数を使用する方法
  • リテラル表記を使用する方法
  • オブジェクト・コンストラクターとプロトタイプを使用する方法

この記事では、単純なフォト・ギャラリー・オブジェクトを実際に作成する例を用いて、上記 3 つの方法をすべて説明します。

この記事を読み進めるには JavaScript 言語の基礎知識が必要です。サンプルを理解するためには、「ダウンロード」セクションからサンプル・コードをダウンロードしてください。JavaScript 言語の基礎をもっと学びたい場合には、「参考文献」に挙げた記事を参照してください。

Object 関数を使用する方法

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;
};

_loopInterval プロパティーの数値

_loopInterval プロパティーの数値を変更すると、各画像の表示時間を増加または減少させることができます。

Gallery オブジェクトのプロパティーは、CurrentIndexImages_loopInterval です。これらを Gallery オブジェクトのプロパティーとして定義するためには、ドット構文を使用してこれらのプロパティーを Gallery オブジェクトに単純に割り当てます。つまりドットと変数名を追加し、その変数に値を割り当てます。リスト 2 で使用しているメソッドは、NextPrevDisplay です。これらを Gallery オブジェクトのメソッドとして定義するためには、ドット構文を使用して各メソッドに独自の関数を割り当てます。

Next メソッドと Prev メソッドはどちらも、Gallery オブジェクトのプロパティーを使用しています。CurrentIndex プロパティーは Images 配列の現在のインデックスが何であるかを明らかにするので、インデックスの値をインクリメントまたはデクリメントすると、CurrentIndex プロパティーは配列内の異なる要素を参照します。Images プロパティーはギャラリーに表示する画像を格納するための配列です。_loopInterval プロパティーはループ処理によってギャラリーの各画像を自動的に 2.5 秒ずつ表示するように設定されています。

この記事で使用する HTML サンプル

リスト 4 の HTML ファイルは、この記事を通して他の例でも使用します。オブジェクトの作成方法に応じて変更されるのは Gallery オブジェクトのみです。

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();">&lt; Previous</a>
    &nbsp;
    <a href="#" onclick="Gallery.Next();">Next &gt;</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 articleoojs.zip197KB

参考文献

学ぶために

製品や技術を入手するために

  • JavaScript 言語の基礎を理解できたら、JavaScript 言語を使用した開発のスピードを高めるための手段として、jQuery ライブラリーが有効です。
  • 皆さんの目的に最適な方法で IBM 製品を評価してください。製品の試用版をダウンロードする方法、オンラインで製品を試す方法、クラウド環境で製品を使う方法、あるいは SOA Sandbox で数時間を費やし、サービス指向アーキテクチャーの効率的な実装方法を学ぶ方法などがあります。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Web development
ArticleID=660403
ArticleTitle=オブジェクト指向の JavaScript コードを作成する
publish-date=04192011