連載:Microsoft AJAX Library&JavaScriptプログラミング

第1回 Microsoft AJAX Libraryで実践オブジェクト指向JavaScript

山田 祥寛(http://www.wings.msn.to/
2007/10/16
Page1 Page2 Page3 Page4

MS AJAX Libによるさまざまなオブジェクト指向構文

 以上、MS AJAX Libで最低限のクラス(コンストラクタやメソッド、プロパティ)を定義する方法と、これをインスタンス化する方法が理解できたと思う。ここからは、さらにオブジェクト指向プログラミングに欠かせない「継承」や「実装(とインターフェイス)」などの手続きについて見ていく。

■MS AJAX Libによる「継承」

 別稿「JavaScriptでオブジェクト指向プログラミング」では、プロトタイプ・ベースのオブジェクト指向における継承機構として、「プロトタイプ・チェーン」を取り上げた。

 プロトタイプ・チェーンは、クラス・ベースのオブジェクト指向とは異なり、動的なメンバの増減にも柔軟に対応できる(つまり、後付けで追加されたメンバも認識できる)という意味で、極めて優れた継承の仕組みではある。しかし同時に、クラス・ベースのオブジェクト指向に慣れた身には、このプロトタイプ・チェーンという概念はなかなか分かりにくいのも事実だ。プロトタイプそのものの概念までは、比較的スムーズに理解できたが、プロトタイプ・チェーンだけはいまいちしっくりとこない、という読者も多かったのではないだろうか。

 そこでMS AJAX Libでは、より直感的に理解しやすい継承の仕組みを提供している。以下のリスト5は、Animalクラスを継承してHamsterクラスを定義する例を示したものだ。

// Wings名前空間の定義
Type.registerNamespace("Wings");

// Wings.Animalクラスの定義(コンストラクタ)
Wings.Animal = function() {};

// Wings.Animalクラスの定義(walkメソッド)
Wings.Animal.prototype = {
  walk : function() {
    window.alert("トコトコ");
  }
};

// Wings.Animalクラスの登録
Wings.Animal.registerClass("Wings.Animal");

// Wings.Hamsterクラスの定義(コンストラクタ)
Wings.Hamster = function() {
  Wings.Hamster.initializeBase(this);
};

// Wings.Hamsterクラスの定義(gnawメソッド)
Wings.Hamster.prototype = {
  gnaw : function() {
    window.alert("ガジガジ…");
  }
};

// Wings.Hamsterクラスの定義と、Wings.Animalクラスの継承
Wings.Hamster.registerClass("Wings.Hamster", Wings.Animal);
リスト5 Animalクラスを継承するHamsterクラス

 MS AJAX Libの継承機構を利用するといっても、何ら難しいことはない。定義に際して理解しておかなければならない構文は、実にリスト5内の太字部分――2点だけだ。

[リスト5− ]initializeBaseメソッドで基底クラスのコンストラクタを実行

 継承機構を利用する場合には、派生クラスのコンストラクタでinitializeBaseメソッドを呼び出す必要がある。initializeBaseメソッドは、基底クラスのコンストラクタを実行するとともに、継承によるメンバの解決(内部的にはメンバのコピー)を行う。initializeBaseメソッドの一般的な構文は、以下のとおりだ。

initializeBase(呼び出し元のインスタンス [, 引数])

 呼び出し元のインスタンスには、一般的には現在のインスタンスを表すthisキーワードを指定すればよい。基底クラスのコンストラクタが引数を要求する場合には、第2引数でこれを配列として渡すことが可能だ。

 例えば、基底クラスのコンストラクタがname、sexという引数を要求する場合、initializeBaseメソッドは以下のように記述できる。

Wings.Hamster = function(name, sex) {
  Wings.Hamster.initializeBase(this, [name, sex]);
};

 ちなみに、ブランケット([〜])はJavaScriptでは配列リテラルを表すためのものである。

[リスト5− ]registerClassメソッドで継承関係を宣言

 実際の継承関係を表すのは、先ほども登場したregisterClassメソッドの役割だ。リスト5の のように、registerClassメソッドの第2引数に継承元のクラスを指定すればよい。これによって、(ここでは)Wings.HamsterクラスがWings.Animalクラスを継承していることが宣言されることになる。

■MS AJAX Libによる継承とプロトタイプ・チェーンの違い

 以上が、MS AJAX Libにおける継承の手続きだ。もちろん、いわゆるVisual BasicやC#のように言語仕様に組み込まれた機能ではないので、記法自体は独特である。しかし、プロトタイプ・チェーンを利用することに比べれば、はるかに直感的な記述ができることがお分かりになるだろう。また、コードを眺めるときにも、継承関係が宣言的に明示されているので分かりやすい。

 もっとも、簡易であるがゆえに注意しなければならない点もある。

 以下は、基底クラスであるWings.Animalに対して動的にメンバを追加した場合のコードを、プロトタイプ・チェーンを利用して記述したものだ。

// Wings.Animalクラスを定義(メンバはwalkメソッドのみ)
var Animal = function() {}

Animal.prototype = {
  walk : function() {
    window.alert("トコトコ");
  }
};

// Wings.Hamsterクラスを定義
// (プロトタイプとしてAnimalオブジェクトをセット)
var Hamster = function() {};

Hamster.prototype = new Animal();

// Wings.Hamsterクラスのプロトタイプに、gnawメソッドを追加
Hamster.prototype.gnaw = function() {
  window.alert("ガジガジ…");
};

var ham = new Hamster();

ham.walk(); // 「トコトコ」
ham.gnaw(); // 「ガジガジ…」

// 基底クラスであるWings.Animalに対してrunメソッドを追加
Animal.prototype.run = function() {
  window.alert("スタタタ…");
};

ham.run(); // 「スタタタ…」
リスト6 プロトタイプ・チェーンによる継承の例

 プロトタイプ・チェーンにおいては、あくまで暗黙的な参照を通じて、基底クラスのメンバが参照される。従って、リスト6の例のように、派生クラスをインスタンス化した後に基底クラスにメンバを追加した場合でも、これを正しく呼び出すことができる。

 一方、MS AJAX Libによる継承を利用した同様の例を見てみよう。

// 名前空間Wingsを宣言
Type.registerNamespace("Wings");

// Wings.Animalクラスを定義(メンバはwalkメソッドのみ)
Wings.Animal = function() {};

Wings.Animal.prototype = {
  walk : function() {
    window.alert("トコトコ");
  }
};

Wings.Animal.registerClass("Wings.Animal");

// Wings.Animalクラスを継承したWings.Hamsterクラスを定義
// (追加メンバはgnawメソッド)
Wings.Hamster = function() {
    Wings.Hamster.initializeBase(this);
};

Wings.Hamster.prototype = {
  gnaw : function() {
    window.alert("ガジガジ…");
  }
};

Wings.Hamster.registerClass("Wings.Hamster", Wings.Animal);

var ham = new Wings.Hamster();

ham.walk(); // 「トコトコ」
ham.gnaw(); // 「ガジガジ…」

// 基底クラスであるWings.Animalに対してrunメソッドを追加
Wings.Animal.prototype.run = function() {
  window.alert("スタタタ…");
};

ham.run(); // ???
リスト7 MS AJAX Libによる継承の例

 リスト7の の結果はどうなるだろう。実はここでエラーとなり、Internet Explorerを使用している場合にはメッセージとして「オブジェクトでサポートされていないプロパティまたはメソッドです。」と表示される。

 これは、MS AJAX Libによる継承が(メソッドの呼び出し時ではなく)インスタンス化のタイミングで解決されていることによる挙動の違いである。MS AJAX Libでは、インスタンス化のタイミングで基底クラスのメンバをコピーすることで、継承関係を解決している。このため、このようにインスタンス化を行った後の動的なメンバの追加を認識することはできない。

 このような挙動の違いは、むしろプロトタイプ・チェーンを理解している人間にとって混乱のもとになる可能性があるので、きちんと理解しておいてほしいところだ(逆に、Visual Basic/C#のような継承機構に慣れた人間にとっては、ほとんど意識する必要がない違いかもしれない)。


 INDEX
  Microsoft AJAX Library&JavaScriptプログラミング
  第1回 Microsoft AJAX Libraryで実践オブジェクト指向JavaScript
    1.Microsoft AJAX Libraryの導入と構造
    2.スクリプト・コアによるクラス定義の基本
  3.MS AJAX Libによるさまざまなオブジェクト指向構文
    4.インターフェイスの定義と実装/[コラム]Typeクラスの実体
 
インデックス・ページヘ  「Microsoft AJAX Library&JavaScriptプログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間