web-dev-qa-db-ja.com

Javascriptでメソッドをオーバーライドする

プロトタイプを使用した場合と使用しない場合のオーバーライド方法の違いを知りたいのですが。考えてみましょう:

例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メソッドをオーバーライドしているのと同じ効果が得られると思います。それとも何か違うことが起こっていますか?

12
codingsplash

最初のメソッドでは、各Animalインスタンスはsleepメソッドとeatメソッドの独自の実装を取得します。

2番目のモデルでは、すべてのインスタンスがsleepメソッドとeatメソッドの同じインスタンスを共有します。

メソッドを共有できるため、2番目のモデルの方が優れています。

10
Arun P Johny

Arunが最初の例で述べたように、新しいインスタンスごとにsleep関数とeat関数を作成しています。 2番目の例では、すべてのインスタンス間で共有されるsleep関数とeat関数は1つだけです。

この場合、2番目の方法の方が優れていますが、最初の方法をいつ使用するか、2番目の方法をいつ使用するかを知っておくとよいでしょう。最初に少し理論を:

注:JavaScriptには4種類の変数があります-privatepublicsharedstatic

プライベート変数は、それらが定義されている関数の外部ではアクセスできません。例えば:

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

8
Aadit M Shah

最初の例のメソッドは、オブジェクトインスタンスで定義されています。

Dogプロトタイプを新しいAnimalインスタンスに設定しているため、Dogsleepおよびeat関数をAnimal。次に、あなたは[〜#〜]定義[〜#〜](NOT [〜#〜]オーバーライド[〜#〜]eatメソッドですインスタンスメソッドとしてDogコンストラクターで、これは[〜#〜] hide [〜#〜]eatで継承されたDogメソッドになりますインスタンス。

次の例を考えてみましょう。

function LittleDog() { }
LittleDog.prototype = Object.create(Dog.prototype);
(new LittleDog()).eat();

上記のコードは、最初の例のコードでanimal eatingに警告します。

そして、2番目のコードでDog eatingに警告します。

0
fardjad

最初の例では、新しいDogインスタンスごとに独自のeatメソッドがあり、2番目の例では、Dog.prototypeeatメソッドが1つだけあります。 Arunが述べたように、Dogの将来のすべてのインスタンス間で共有されます。

これが唯一の"tricky"これら2つの違いです。ただし、メモリの大量消費とリークを回避するために、prototypeでメソッドを定義することをお勧めします。

0
happyCoda