クラスはオブジェクトを拡張しますか?
ご存じのように、すべてのオブジェクトは通常Object.prototype
から継承され、hasOwnProperty
などの「ジェネリック」なオブジェクトメソッドにアクセスできます。
たとえば
class Rabbit {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
// hasOwnProperty method is from Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
ただし、明示的に「class Rabbit extends Object
」のように指定すると、"class Rabbit"
という簡単な指定とは異なる結果になりますか?
違いは何ですか?
以下にそのようなコードの例を示します(機能しません - なぜですか? 修正してください)
class Rabbit extends Object {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // Error
まず、後者のコードが機能しない理由を見てみましょう。
その理由は、実行しようとすると明らかになります。継承クラスのコンストラクターはsuper()
を呼び出す必要があります。そうでなければ、「this
」は「定義」されません。
そこで修正版を次に示します。
class Rabbit extends Object {
constructor(name) {
super(); // need to call the parent constructor when inheriting
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
しかし、まだ全部ではありません。
修正した後でも、「class Rabbit extends Object
」とclass Rabbit
との間には重要な違いがあります。
ご存じのように、「extends」構文は2つのプロトタイプを設定します。
- コンストラクター関数の「
prototype
」間(メソッド向け)。 - コンストラクター関数自体間(静的メソッド向け)。
class Rabbit extends Object
の場合、それは次のことを意味します。
class Rabbit extends Object {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
そのため、Rabbit
はRabbit
を介して次の方法でObject
の静的メソッドへのアクセスを可能にするようになりました。
class Rabbit extends Object {}
// normally we call Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
ただし、extends Object
がない場合、Rabbit.__proto__
はObject
に設定されません。
デモを次に示します。
class Rabbit {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
// error, no such function in Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
その場合、Rabbit
はObject
の静的メソッドへのアクセスを提供しません。
ちなみに、Function.prototype
にもcall
、bind
などの「ジェネリック」な関数メソッドがあります。これらは結局のところどちらの場合でも利用できます。これは、組み込みのObject
コンストラクターの場合、Object.__proto__ === Function.prototype
であるためです。
図を次に示します。
つまり、一言で言えば、2つの違いがあります。
class Rabbit | クラス Rabbit は Object を拡張 |
---|---|
– | コンストラクタにsuper() を呼び出す必要がある |
Rabbit.__proto__ === Function.prototype |
Rabbit.__proto__ === Object |