連載: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で汎用的な型システムを提供するのがスクリプト・コアの役割であり、MS AJAX Libプログラミングを理解するうえでこの部分の理解は欠かせない。本節ではまず、スクリプト・コア(厳密には、その実装であるTypeクラス)を利用した、オブジェクト指向構文の基本について見ていくことにしよう。

■MS AJAX Libによるクラスの定義

 それではさっそく、MS AJAX Libを利用した具体的なクラス定義のコードを見てみよう。以下は、MS AJAX Libで中身を持たない、最も単純なクラスの例――Animalクラス(名前空間は“Wings”)を定義した例だ。

Type.registerNamespace("Wings");

Wings.Animal = function() {};

Wings.Animal.registerClass("Wings.Animal");
リスト1 MS AJAX Libにおける最もシンプルなクラス定義の例(Animal.js)

 別稿「JavaScriptでオブジェクト指向プログラミング」で示したリスト1と比較すれば分かるように、コンストラクタを関数リテラルで定義している点は、標準的なJavaScriptの構文そのままである。MS AJAX Lib固有の構文としてご注目いただきたいのは、リスト1の太字で示した の2カ所だ。

名前空間を宣言するのはType.registerNamespaceメソッドの役割

 名前空間とは、ライブラリ内のクラスを分類するための機能だ。Visual BasicやC#を利用している読者ならば当たり前ともいえる概念であるが、JavaScriptは標準では名前空間に対応していない。

 そこでMS AJAX Libでは、Typeオブジェクトを介して、疑似的に名前空間の機能を提供している。名前空間を定義する手順は簡単、Type.registerNamespaceメソッドで作成したい名前空間を宣言するだけでよい。ここでは、「Wings」と単階層の名前空間を定義しているが、

Type.registerNamespace("To.Wings.Msn");

とすることで、多階層の名前空間を定義することも可能だ。名前空間に属するクラスを定義するにも、

Wings.Animal = function() {};

のように「名前空間名.クラス名」の完全修飾名で指定すればよいだけだ。

 もっとも、別稿「JavaScriptでオブジェクト指向プログラミング」のリスト1と比べてみると、コンストラクタの記述は、

var Wings.Animal = function() {};

とvar命令付きで記述すべきではないのかと思われる方もいるかもしれない。なるほど、Wings.Animalを1つのグローバル変数と見なすと、こちらがより正しい記述にも思われるかもしれないが、結論からいってしまえば、これは不可である。

 実は、MS AJAX Libでは中身が空のオブジェクトを内部的に生成することで、疑似的に「名前空間的な」機能を実現している。つまり、Wings.Animalとは内部的にはWingsオブジェクトのAnimalプロパティを表していることになるわけだ。当然ではあるが、プロパティ値の設定に変数宣言を表すvar命令を使用することはできない。ささいなことではあるが、間違えやすいポイントであるので、注意していただきたい。

クラスをMS AJAX Libに登録するregisterClassメソッド

 MS AJAX Libでは、MS AJAX Lib上で利用可能なクラスとして認識できるように、これを登録するという作業が必要になる。registerClassメソッドを呼び出す構文は、以下のとおりだ。

registerClass("クラスの完全修飾名");

 これで、Wings.AnimalクラスがMS AJAX Lib上で利用可能なクラスとして認識されたことになる*2

*2 厳密にはregisterClassメソッドによる登録作業を行わなくても、クラスを利用することは可能だ。つまり、インスタンス化して、配下のメソッドやプロパティを呼び出すことができる。しかしその場合には、後述する「継承」機能をはじめ、Typeオブジェクトが提供するそのほかの機能を利用できなくなるので、注意してほしい。

■定義したクラスを利用する方法

 次に、MS AJAX Libで定義したWings.Animalクラスを、任意のページ(.aspxファイル)から呼び出してみよう。

<asp:ScriptManager ID="manager" runat="server">
  <Scripts>
    <asp:ScriptReference Path="Animal.js" />
  </Scripts>
</asp:ScriptManager>
  ……中略……
<script type="text/javascript">
  var anim = new Wings.Animal();
</script>
リスト2 Wings.Animalクラスを呼び出すためのコード(Animal.aspx)

 インスタンス化そのものは標準的なnew演算子でもって行えるが、MS AJAX Lib固有のポイントもあるので要注目だ。

[リスト2− ]ScriptManagerコントロールを配置する

 ScriptManagerコントロールは、ASP.NET AJAXの動作に必要なクライアントサイド・スクリプトの出力/生成を担うコントロールだ。

 UpdatePanelやUpdateProgress/TimerなどのAJAX Extensionsコントロールだけを利用している方は、とにかく「AJAX Extensionsコントロールを利用する場合に必要なもの」とおまじないのように覚えている存在であるかもしれない。しかし、ScriptManagerコントロールは何もAJAX Extensionsコントロールの占有物ではない。MS AJAX Libの機能を利用する場合にも、ScriptManagerコントロールの配置は必須である*3。これは、先ほど登場したTypeオブジェクトなど、名前空間やクラスの定義に必要なライブラリを、ScriptManagerコントロールが内部的に出力しているためだ。

*3 厳密には、<script>タグで必要な.jsファイルを手動でインポートしても構わない。しかし、.aspxファイル上であえて<script>タグを利用する意味はないだろう。

 また、ページ内で利用するMS AJAX Lib以外のスクリプト(この場合はAnimal.js)は、あらかじめScriptManager.Scriptsプロパティに登録しておく必要がある。Scriptsプロパティを指定するには、プロパティ・ウィンドウのScriptsプロパティ右端の[...]をクリックすればよい。これにより<asp:ScriptReference>要素が生成される。


[ScriptReferenceコレクションエディタ]ダイアログ

 上の画面のような[ScriptReferenceコレクションエディタ]ダイアログが表示されるので、ダイアログ左下の[追加]ボタンをクリックし、右のプロパティ・グリッドからPathプロパティに「Animal.js」へのパスを指定すればよい。

[リスト2− ]名前空間に属するクラスをインスタンス化する

 名前空間に属するクラス(リスト2の場合は、Wings名前空間のAnimalクラス)をインスタンス化する場合には、必ず「名前空間名.クラス名」の完全修飾名として指定する必要がある(名前空間を省略することはできない)ので、要注意だ。

 もっとも、前述したように、MS AJAX Libの名前空間が内部的にはオブジェクトであることを理解していれば、特定の名前空間を略記したいという場合に、withブロックを使って以下のように記述することも可能ではある。

with (Wings) {
  var anim = new Animal();
}
リスト3 withブロックを利用して、疑似的に名前空間を略記する例

 使用している名前空間が複数にわたっていたり、あるいは、そもそも使用しているクラスが1つであるようなケースではあまり“うまみ”がないかもしれないが、同一の名前空間に属しているクラスを複数利用するようなケースでは有効な記法であるので、お試しいただきたい。

■プロパティ/メソッドを定義する

 次に、先ほどリスト1で定義したAnimalクラス(Animal.js)を修正して、name(名前)/sex(性別)プロパティ、そして、toStringメソッド(Animalクラスの文字列表現を取得)などのメンバを追加してみよう。具体的なコードは、以下のとおりだ。

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

// Wings.Animalクラスのコンストラクタ
Wings.Animal = function(name, sex) {
  this._name = name;
  this._sex  = sex;
};

// Wings.Animalクラスのメンバ定義
// (name/sexプロパティ、toStringメソッド)
Wings.Animal.prototype = {
  get_name : function() {
    return this._name;
  },
  set_name : function(name) {
    this._name = name;
  },
  get_sex : function() {
    return this._sex;
  },
  set_sex : function(sex) {
    this._sex = sex;
  },
  toString : function() {
    return this._name + " " + this._sex;
  }
};

// Wings.Animalクラスの登録
Wings.Animal.registerClass("Wings.Animal");
リスト4 Animalクラスにname/sexプロパティ、toStringメソッドを追加した例(Animal.js)
「get_name : function() { ……」という記述はオブジェクト・リテラルを使ったプロトタイプの定義方法である。詳しくは「JavaScriptでオブジェクト指向プログラミング」を参照していただきたい。

 メソッドの定義については、MS AJAX Lib固有のポイントはないので、本稿では解説は割愛する。ここで注目していただきたいのは、プロパティを定義している部分だ(リスト4内の太字部分)。

 別稿「JavaScriptでオブジェクト指向プログラミング」ではクラス配下で定義されたメンバ変数を「プロパティ」と呼んでいたわけであるが、MS AJAX Libではこのような外部に直接公開されたメンバ変数のことを「フィールド」と呼んで、いわゆるプロパティとは区別している(以降も用語としては厳密に区別するので要注意だ)。

 では、プロパティを定義するにはどうしたらよいのか。プロパティを定義するには、プロパティ値を格納するためのプライベート変数(クラス内部からしかアクセスできない変数)と、プライベート変数に外部からアクセスするためのアクセサ・メソッド(Accessor Method)を定義しなければならない。

 アクセサ・メソッドとは、名前のとおり、クラス内のメンバ変数にアクセスするためのメソッドで、参照用のメソッドをゲッター・メソッド(Getter Method)、設定用のメソッドをセッター・メソッド(Setter Method)と呼ぶ場合もある*4

*4 Visual Basic/C#に慣れている方は、これら言語のプロパティ構文と比較してみれば理解しやすいだろう。ただし、JavaScriptには専用のプロパティ構文は存在しないので、ゲッター・メソッドとセッター・メソッドとが独立したメソッドとして定義されている点が、Visual Basic/C#とは異なる。

 ここでは、name/sexプロパティを格納するためのプライベート変数として_name/_sexを、name/sexプロパティにアクセスするためのアクセサ・メソッドとしてget_name/set_name、get_sex/set_sexメソッドを定義しているわけだ。

 ただし、プライベート変数とはいっても、JavaScriptにはVisual Basic/C#のアクセス修飾子に相当する機能は存在しない。そこで、JavaScriptでは、プライベート変数であることを表すために、変数名を「_」(アンダースコア)で始めるのが慣例的だ。もちろん、これはあくまで命名上の慣例であって、これによってクラス外部からのアクセスを制限できるものではないが、少なくともこれがプライベート・メンバであることを識別できる。今後、MS AJAX LibやControl Toolkitに含まれるJavaScriptのコードを参照する機会があるかもしれないが、その場合にも「_」で始まるメンバを見掛けたら、これを直接にアプリケーションから利用するべきではない、ということを覚えておこう。

 そして、プライベート変数に対して値を参照/設定する役割を担うのが、前述したアクセサ・メソッドの役割だ。アクセサ・メソッドのシグニチャはそれぞれ以下の規則に従う必要がある(この命名規則に従っていない場合、今後、MS AJAX Lib固有の機能を利用したクラス呼び出しで、正しくプロパティ値が設定できなくなる可能性があるので要注意)。

function get_プロパティ名() {……} // ゲッター・メソッド
function set_プロパティ名(仮引数) {……} // セッター・メソッド

 ここでは、単にプライベート変数の値を参照/設定しているだけであるが、もちろん、値を設定するに際してその内容を検証したり、取得する前にこれを加工したり、といった処理を加えることも可能だ。また、読み取り専用のプロパティを定義したい場合には、ゲッター・メソッドだけを記述し、書き込み専用のプロパティを作成したい場合には、セッター・メソッドだけを定義するようにすればよい。

 プロパティの構文自体は以上のとおりであるが、ここで、「ではメンバ変数を公開する場合に、フィールドを利用するべきか、プロパティを利用するべきか」という疑問がわいてくるかもしれない。確かに、プロパティを利用することで、値の設定/参照に際してさまざまな処理を追加したり、読み取り/書き込みの規則を明確に定義したりできる、というメリットがある。しかし、本サンプルのように読み書きを許可しており、アクセサ・メソッドでも値の単純な取得/設定を行っているだけというならば、フィールドでも十分ではないかという疑問がわいてくるわけだ。

 この疑問に対して、結論からいってしまうならば、MS AJAX Libでクラスを定義する場合には「プロパティ」を利用するのが好ましい。

 単純なクラスを定義する場合には、なるほど、フィールドを利用しても問題はない。しかし、クライアント・コンポーネント(コントロール)を定義する場合には、公開するメンバ変数はプロパティとして定義「しなければならない」(コントロールについては後の回で詳述する)。そうでなくとも、将来的にプロパティとしての細かな制御が必要になった場合に、外部に対するインターフェイスが変更になってしまうインパクトを考えれば、多少コードが長くなっても、最初からプロパティで統一しておくのがむしろシンプルといえるだろう。


 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 記事ランキング

本日 月間