2007年11月21日水曜日

JavaScript と 継承 2

OOP と JavaScript における継承について、JavaScript と継承 の続きです。

__proto__ プロパティ

Netscape Navigator 4.x 及び Netscape 6 では オブジェクトの __proto__ プロパティにより、オブジェクトのプロトタイプを確認できます。
例を以下に示します。

※ __proto__ プロパティは Internet Explorer ではサポートされていません。
function Shape() {
this.borderWidth = 5;
}

function Square() {
this.edge = 12;
}

// Squeare のプロトタイプとして Shape を呼出す
Square.prototype = new Shape;

// Square のインスタンス生成
myPicture = new Square;

// myPicture のプロトタイププロパティを確認
alert(myPicture.__proto__);

// スーパークラスから継承したプロパティが呼出される
alert(myPicture.borderWidth);
///// 5
この例において、ローカル変数で定義されていないプロパティ boderWidth が呼出されると、__proto__ プロパティがプロパティを探すオブジェクト ( この場合 Shape) を指示します。

また、以下の例のように、オブジェクトの、__proto__ プロパティを次々とたどることができます。
function Language(){};

function English(){};
English.prototype = new Language;

function Alphabet(){};
Alphabet.prototype = new English;

newCharacter = new Alphabet();

alert(newCharacter.__proto__ == Alphabet.prototype);
///// true

alert(newCharacter.__proto__.__proto__ == English.prototype);
///// true

alert(newCharacter.__proto__.__proto__.__proto__ == Language.prototype);
//true

instanceOf メソッドの実装

__proto__ プロパティが利用できる NS では、以下のように、オブジェクトが特定のコンストラクタから生成されたインスタンスかを調べる instanceOf メソッドを定義できます。
// オブジェクトがコンストラクタのインスタンスかどうかを調べる関数
// object, constructorName: コンストラクタ名
function instanceOf(object, constructorName) {
while (object != null) {
if (object == constructorName.prototype) return true;
object = object.__proto__;
}
return false;
}
これを前出の例に適用してみます。newCharacter は Alphabet, English, Language の全てのインスタンスですから、この関数を適用すると以下のようになります。
alert(instanceOf(newCharacter, Alphabet));
///// true

alert(instanceOf(newCharacter, English));
///// true

alert(instanceOf(newCharacter, Language));
///// true

for...in

オブジェクトのプロパティ名は、
for (プロパティ in オブジェクト名)
で参照できます。コンストラクタ employee により生成された newPerson オブジェクトのプロパティ名は以下のように得られます。
function employee() {
this.dept = "HR";
this.manager = "John Johnson";
}

function printProp() {
var newPerson = new employee();
// ken オブジェクトのプロパティを順に表示
for (property in newPerson) {
alert(property);
}
}

printProp();
///// dept
///// manager
以下のように Employee のスーパークラス Person を定義し、Employee のプロトタイプとした場合に、オブジェクトのスーパークラスのプロパティもたどるのか試してみます。
function Person(){
this.animal = 'human';
}

function Employee() {
this.dept = 'HR';
this.manager = 'John Johnson';
}
Employee.prototype = new Person;

function printProp3() {
var Ken = new Employee();
for(prop in Ken) alert(prop);
}

printProp3();
///// dept
///// manager
///// animal
これより、for...in では、オブジェクトのスーパークラスのプロパティもたどることが分かりました。

あるオブジェクトに指定したプロパティが存在するかどうかをチェックするには、hasOwnProperty, や propertyIsEnumerable メソッドを使います。
上記の例に続く以下の例を見てみます。

Ken = new Employee();

// dept プロパティを持つかチェック
alert(Ken.hasOwnProperty('dept'));
///// true

// name プロパティを持つかチェック
alert(Ken.hasOwnProperty('name'));
///// false

Ken.children = new Array('taro', 'sara');

// 0 番目の要素があるか
alert(Ken.children.propertyIsEnumerable(0));
///// true

// children は 3 番目の要素があるか
alert(Ken.children.propertyIsEnumerable(3));
///// false
参考: Object-Oriented Programming with JavaScript, Part I: Inheritance