を実行するnew Catと、から継承する空のオブジェクトCat.prototypeが作成されます。何Cat.prototypeですか?まだ変更していないため、空のオブジェクトです。
コンストラクター内で、を割り当ててCat.prototype = new Mammal();います。の次のインスタンスはCat、このインスタンスから継承しMammalます。Mammalただし、2番目のインスタンスを作成すると、3番目のCatインスタンスが継承する別のインスタンスも作成され、以下同様に続きます。
最終的にこの継承チェーンになります(はのcatXx番目のインスタンスでCatありmammalX、はのx番目のインスタンスですMammal):
cat0 -> Object
cat1 -> mammal0 -> Mammal.prototype
cat2 -> mammal1 -> Mammal.prototype
...
各Catインスタンスには独自のプロトタイプがありますが、これはプロトタイプの使用目的(共通コードの共有)とはまったく逆です。それほど大したことではないように見えるかもしれませんが、次のようないくつかの結果があります。
- メモリ使用量の増加:(ほぼ)各
Catインスタンスには対応するMammalインスタンスがあるため、2Nの代わりにオブジェクトがありますN + 1。
- 継承テストは壊れます:
instanceofプロトタイプを比較することによって機能し、のプロトタイプは(複数のインスタンスを作成した後)cat0とは異なるため、を生成します。Cat.prototypecat instanceof Catfalse
本当に必要な継承チェーンは次のとおりです。
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を参照してください。