を実行するnew Cat
と、から継承する空のオブジェクトCat.prototype
が作成されます。何Cat.prototype
ですか?まだ変更していないため、空のオブジェクトです。
コンストラクター内で、を割り当ててCat.prototype = new Mammal();
います。の次のインスタンスはCat
、このインスタンスから継承しMammal
ます。Mammal
ただし、2番目のインスタンスを作成すると、3番目のCat
インスタンスが継承する別のインスタンスも作成され、以下同様に続きます。
最終的にこの継承チェーンになります(はのcatX
x番目のインスタンスでCat
ありmammalX
、はのx番目のインスタンスですMammal
):
cat0 -> Object
cat1 -> mammal0 -> Mammal.prototype
cat2 -> mammal1 -> Mammal.prototype
...
各Cat
インスタンスには独自のプロトタイプがありますが、これはプロトタイプの使用目的(共通コードの共有)とはまったく逆です。それほど大したことではないように見えるかもしれませんが、次のようないくつかの結果があります。
- メモリ使用量の増加:(ほぼ)各
Cat
インスタンスには対応するMammal
インスタンスがあるため、2N
の代わりにオブジェクトがありますN + 1
。
- 継承テストは壊れます:
instanceof
プロトタイプを比較することによって機能し、のプロトタイプは(複数のインスタンスを作成した後)cat0
とは異なるため、を生成します。Cat.prototype
cat instanceof Cat
false
本当に必要な継承チェーンは次のとおりです。
cat0 -> Mammal.prototype
cat1 -> Mammal.prototype
cat2 -> Mammal.prototype
...
コンストラクター関数内でプロトタイプに値を割り当てたり(またはプロトタイプを上書きしたり)しないでください。コンストラクター関数は、インスタンス固有のプロパティのみを設定する必要があります(静的プロパティを変更したい場合もありますが、これらはあまり一般的ではありません)。
コンストラクター関数の外部でプロトタイプをセットアップします。
function Mammal() {}
Mammal.prototype.hasHair = function() { return true; }
function Cat() {
Mammal.apply(this, arguments);
}
Cat.prototype = Object.create(Mammal.prototype);
Cat.prototype.constructor = Cat;
Object.create
引数として渡したオブジェクトを継承するオブジェクトを作成します。MDNを参照してください。