クラスは Object を拡張しますか?
私たちが知っている通り、すべてのオブジェクトは通常 Object.prototype を継承しており、“一般的な” オブジェクトメソッドにアクセスできます。
ここでのデモンストレーションのように:
class Rabbit {
constructor(name) {
this.name = name;
}
}
let rabbit = new Rabbit("Rab");
// hasOwnProperty メソッドは Object.prototype からです
// rabbit.__proto__ === 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') ); // true
もし動かない場合、コードを直してください。
解答は2つパートがあります。
最初に、簡単な方は、継承しているクラスはコンストラクタで super() を呼ぶ必要があるということです。そうでなければ "this" が “定義済み” になりません。
なので、次のように直します:
class Rabbit extends Object {
constructor(name) {
super(); // 継承しているとき、親コンストラクタを呼ぶ必要があります
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 経由で Object の静的メソッドにアクセスすることができます。:
class Rabbit extends Object {}
// 通常は Object.getOwnPropertyNames と呼びます
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
また、extends を使わない場合 class Rabbit は2つ目の参照を持ちません。
比較してみてください:
class Rabbit {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
// エラー、Rabbit にこのような関数はありません
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
シンプルな class Rabbit では Rabbit 関数は同じプロトタイプを持っています。
class Rabbit {}
// (2) の代わりに、これは正しいです:
alert( Rabbit.__proto__ === Function.prototype );
ところで、Function.prototype は “一般的な” 関数メソッドを持っています。例えば call, bind などです。それらは究極的には両方のケースで利用可能です。なぜなら、組み込みの Object コンストラクタに対して、Object.__proto__ === Function.prototype だからです。
これはその図です:
従って、まとめると2つの違いがあります。:
| class Rabbit | class Rabbit extends Object |
|---|---|
| – | コンストラクタで super() を呼ぶ必要がある |
Rabbit.__proto__ === Function.prototype |
Rabbit.__proto__ === Object |