クラスは 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 |