プロトタイプを使用した場合と使用しない場合のオーバーライド方法の違いを知りたいのですが。考えてみましょう:
例1:
function Animal() {
this.sleep = function () {
alert("animal sleeping");
};
this.eat = function () {
alert("animal eating");
};
}
function Dog() {
this.eat = function () {
alert("Dog eating");
};
}
Dog.prototype = new Animal;
var dog = new Dog;
dog.eat();
例2:
function Animal() { }
function Dog() { }
Animal.prototype.sleep = function () {
alert("animal sleeping");
};
Animal.prototype.eat = function () {
alert("animal eating");
};
Dog.prototype = new Animal;
Dog.prototype.eat = function () {
alert("Dog eating");
};
var dog = new Dog;
dog.eat();
どちらの例でも、Dog
クラスがAnimal
クラスのeatメソッドをオーバーライドしているのと同じ効果が得られると思います。それとも何か違うことが起こっていますか?
最初のメソッドでは、各Animal
インスタンスはsleep
メソッドとeat
メソッドの独自の実装を取得します。
2番目のモデルでは、すべてのインスタンスがsleep
メソッドとeat
メソッドの同じインスタンスを共有します。
メソッドを共有できるため、2番目のモデルの方が優れています。
Arunが最初の例で述べたように、新しいインスタンスごとにsleep
関数とeat
関数を作成しています。 2番目の例では、すべてのインスタンス間で共有されるsleep
関数とeat
関数は1つだけです。
この場合、2番目の方法の方が優れていますが、最初の方法をいつ使用するか、2番目の方法をいつ使用するかを知っておくとよいでしょう。最初に少し理論を:
注:JavaScriptには4種類の変数があります-private
、public
、shared
、 static
。
プライベート変数は、それらが定義されている関数の外部ではアクセスできません。例えば:
function f() {
var x; // this is a private variable
}
パブリック変数は、関数内のthis
オブジェクトで定義されます。例えば:
function f() {
this.x; // this is a public variable
}
共有変数は、関数のprototype
で共有されます。例えば:
function f() {}
f.prototype.x; // this is a shared variable
静的変数は、関数自体のプロパティです。例えば:
function f() {}
f.x; // this is a static variable
ほとんどの場合、コンストラクターのすべてのインスタンスがそれらを共有するため、コンストラクター関数のメソッドを共有メソッドとして宣言するのが最善です。ただし、メソッドがプライベート変数にアクセスする必要がある場合は、パブリックメソッド自体として宣言する必要があります。
注:これは私自身の命名法です。多くのJavaScriptプログラマーはそれに固執していません。他の人はダグラス・クロックフォードの命名法に従っているようです: http://javascript.crockford.com/private.html
JavaScriptでのプロトタイプの継承について詳しくは、次の回答をお読みください: https://stackoverflow.com/a/8096017/78374
最初の例のメソッドは、オブジェクトインスタンスで定義されています。
Dog
プロトタイプを新しいAnimal
インスタンスに設定しているため、Dog
はsleep
およびeat
関数をAnimal
。次に、あなたは[〜#〜]定義[〜#〜](NOT [〜#〜]オーバーライド[〜#〜])eat
メソッドですインスタンスメソッドとしてDog
コンストラクターで、これは[〜#〜] hide [〜#〜]eat
で継承されたDog
メソッドになりますインスタンス。
次の例を考えてみましょう。
function LittleDog() { }
LittleDog.prototype = Object.create(Dog.prototype);
(new LittleDog()).eat();
上記のコードは、最初の例のコードでanimal eating
に警告します。
そして、2番目のコードでDog eating
に警告します。
最初の例では、新しいDog
インスタンスごとに独自のeat
メソッドがあり、2番目の例では、Dog.prototype
にeat
メソッドが1つだけあります。 Arunが述べたように、Dog
の将来のすべてのインスタンス間で共有されます。
これが唯一の"tricky"これら2つの違いです。ただし、メモリの大量消費とリークを回避するために、prototype
でメソッドを定義することをお勧めします。