第4回 JavaScriptでオブジェクト指向プログラミング:連載:Ajax時代のJavaScriptプログラミング再入門(4/4 ページ)
最終回となる今回は、JavaScriptでの本格的コーディングに欠かせない<プロトタイプ・ベースのオブジェクト指向>について解説。
以上、最終回の今回はJavaScriptによるオブジェクト指向について解説した。JavaScriptのオブジェクト指向は「プロトタイプ・ベースのオブジェクト指向」と呼ばれ、従来の「クラス・ベースのオブジェクト指向」に精通した開発者であればあるほど、なじみにくく感じる概念かもしれない。しかし、あまり難しく考える必要はない。
繰り返しではあるが、JavaScriptではクラスという抽象的な概念の代わりに、すべての概念が実体を持ったオブジェクト(インスタンス)で表されるというだけだ。クラス・ベースのオブジェクト指向言語では、クラスを基にオブジェクトを作成していたところが、JavaScriptではオブジェクトを基に異なるオブジェクトを作成することになっただけなのだ。この1点さえ分かってしまえば、実は、プロトタイプ・ベースのオブジェクト指向も恐れるに足らない。
本稿が、JavaScriptに対して苦手意識を持つ開発者諸氏にとって、これを克服するきっかけとなれば幸いである。
[コラム]オブジェクトと連想配列
本文で、オブジェクト・リテラルの「{名前 : 値, ……}」という表記は、JavaScriptにおける連想配列(ハッシュ)の記法でもあると述べた。これを聞いて、それではオブジェクトはそもそも連想配列なのではないかと考えた方はご明察。
そのとおり、JavaScriptではオブジェクトと連想配列との間に厳密な区別はない。便宜上、オブジェクトと連想配列を(キーワードとして)使い分けることはあるにせよ、オブジェクトと連想配列とは、JavaScriptの世界においては同一の概念なのである。従って、以下の記述も、意味的に完全に等価である。
また、オブジェクトのメンバにアクセスするにも、ドット演算子を利用するばかりではない――連想配列のブランケット構文を利用してアクセスすることが可能である。逆もしかり、連想配列の各キーに対してドット演算子でアクセスすることも可能だ。そう、連想配列はオブジェクトであり、オブジェクトは連想配列であるのだから*5。従って、以下の2文は、これまた等価の命令である。
*5 もっとも、厳密にはブランケット構文とドット演算子とには違いもある。例えば、「123」のようなキー(メンバ名)はドット演算子では認められないが、ブランケット構文では可である。なぜなら、ブランケット構文ではキー名は文字列として扱われるが、ドット演算子では識別子(第2回を参照)として扱われるからである。つまり、ドット演算子を利用する場合、メンバ名は変数名と同様の制約を課せられることになる。
もっと行ってみよう。実は、先ほどのリスト9でさりげなくfor…inループでオブジェクト配下のメンバを列挙するコードを表してみたが、オブジェクトが連想配列であることを理解してみれば、これまた直感的に理解できる内容であるはずだ。for…inループは、連想配列から順に配下のキーを取り出しているというわけだ。
もちろん、先ほどのリストでも示したように、取り出したキーによってブランケット構文でアクセスすることで、メンバの内容を取得することもできる。
ただし、for…in命令による列挙は、すべてのメンバが対象となるわけではないので、注意してほしい。
var ary = new Array();
for (name in ary) { window.alert(name); }
このコードは、Arrayオブジェクトに属するメンバを順に列挙することを目的としたものである(Arrayオブジェクトではconcat、join、pop、pushなどのメソッドが公開されているはずである)。しかし、結果はというと、「メンバは一切表示されない」。これはどういうことなのだろうか。
実は、これはArrayオブジェクトのprototypeプロパティがDontEnum属性でマーキングされていることから生じる現象である。DontEnum属性が付与されたメンバは、for…inループによる列挙の対象から外される。そのため、prototypeプロパティ(プロトタイプ・オブジェクト)で定義されたすべてのメンバはfor…inループでは表示されないというわけだ。この事情は、ほかのオブジェクトのメンバについても同様である。
ちなみに、JavaScriptではそのほかにもメンバの特性を決めるための属性として、以下のようなものを用意している。
属性名 | 機能概要 |
---|---|
DontDelete | delete演算子による削除の禁止 |
DontEnum | for…inループによる列挙の対象外 |
Internal | 内部メンバ(直接のアクセスを禁止) |
ReadOnly | 読み取り専用(値の設定を禁止) |
JavaScriptの内部属性 |
ただし、これらの属性はあくまでJavaScript内部的なもので、アプリケーション開発者が直接に触れることはできない(例えば、自作オブジェクトのメンバに対してDontEnum属性を追加したり、組み込みオブジェクトのメンバからDontDelete属性を外したりということはできない)。
Copyright© Digital Advantage Corp. All Rights Reserved.