2012-03-19 10 views
137

javascriptオブジェクトの作成では、コンストラクタ関数またはプロトタイプのいずれかにメソッド宣言を置くことができます。たとえば、NameプロパティとBarkメソッドを持つDogクラスが必要です。私は、コンストラクタ関数に樹皮メソッドの宣言を置くことができる。コンストラクタ関数でのjavascriptオブジェクトメソッドの宣言とプロトタイプ

var Dog = function(name) { 
    this.Name = name; 
    this.Bark = function() { 
     alert(this.Name + " bark"); 
    }; 
} 

またはIプロトタイプオブジェクトのメソッドとして置くことができる:

var Dog = function(name) { 
    this.Name = name; 
} 

Dog.prototype.Bark = function() { 
    alert(this.Name + " bark"); 
}; 

Iタイプ犬のオブジェクトをインスタンス化するとき、両方のアプローチはうまく動作するように見える:

var dog = new Dog("Fido"); 
dog.Bark(); //Both approaches show "Fido bark" 

は、私は他の上にこれらのいずれかの方法を好むでしょうか?どちらか一方を使用することに利点がありますか?背後では、これらの2つのアプローチはまったく同じことをすることになりますか?ほとんどの人がどのアプローチを好む傾向がありますか?

ありがとうございました。

+1

... [「プロトタイプ」と「this」のJavascriptでの使用」(http://stackoverflow.com/q/310870/1048572)et al – Bergi

答えて

200

この例では、プロトタイプアプローチを使用する必要があります。一般に、それは依存する。最初のアプローチ(コンストラクタのメソッドを初期化する)の主な利点は、メソッドのコンストラクタ内で定義されたローカル変数を利用してクロージャを利用できることです。これらの変数は、コンストラクタ関数の外部で直接アクセスすることはできませんので、効果的に "プライベート"です。つまり、これらの変数がオブジェクトのプロパティとして定義されている場合よりもクリーンです。親指のいくつかの一般的なルール:

  • あなたの方法には、プロトタイプのアプローチを使用し、その後、(あなたの例ではない)あなたのコンストラクタで定義されたローカル変数を使用しない場合。
  • Dogのロットを作成する場合は、プロトタイプアプローチを使用します。このようにして、すべての "インスタンス"(すなわち、Dogコンストラクタによって作成されたオブジェクト)は、1組の関数を共有しますが、コンストラクタの方法では、より多くのメモリを使用してDogコンストラクタが呼び出されるたびに
  • Dogの数を少なくして、コンストラクタ内のローカルの「プライベート」変数を使用するとコードが改善されることがわかっている場合は、これがより良いアプローチかもしれません。あなたの判断を使用し、パフォーマンスやメモリ消費が大きな問題であれば、いくつかのベンチマークを行います。

ローカルプライベートコンストラクタ変数へのアクセスを必要とするメソッドだけがコンストラクタで定義され、他のメソッドがプロトタイプに割り当てられるハイブリッドアプローチを使用することは可能です。

たとえば、以下のコードでは、コンストラクタ内でローカル変数を使用して、実際の数値を非公開にしながらこの犬が吠えた回数を記録しています。そのため、吠える関連のメソッドはコンストラクタ内で定義されます。テール・ワギングは、バーク数にアクセスする必要がないため、そのメソッドをプロトタイプで定義できます。

var Dog = function(name) { 
 
    this.name = name; 
 

 
    var barkCount = 0; 
 

 
    this.bark = function() { 
 
     barkCount++; 
 
     alert(this.name + " bark"); 
 
    }; 
 

 
    this.getBarkCount = function() { 
 
     alert(this.name + " has barked " + barkCount + " times"); 
 
    }; 
 
}; 
 

 
Dog.prototype.wagTail = function() { 
 
    alert(this.name + " wagging tail"); 
 
}; 
 

 
var dog = new Dog("Dave"); 
 
dog.bark(); 
 
dog.bark(); 
 
dog.getBarkCount(); 
 
dog.wagTail();

+3

Nice answer、Tim! –

+0

@Tim Down答えにはっきりしているので、ローカル変数が混在していると、コンストラクタのメソッドを使うのは良いことです。 – Sethen

+3

@SethenMaleno:私は変数へのアクセスの速度を本当に考慮していませんでした。これは、通常は大きな考慮すべきではありません。コンストラクターでメソッドを作成することに主な議論をする主な議論は、オブジェクトにアクセスできない方が良いと思われるプロパティーをオブジェクトに定義するのではなく、それらの変数を非公開にすることです。 –

8

私が見たjavascriptコードの大部分は、プロトタイプメソッドを使用しています。私は、私が頭の上から考えることができるこの3つの理由があると思います。

最初は、すべてのクラスが巨大なコンストラクタであることを避けることです:コンストラクタロジックはコンストラクタ関数に入り、他のメソッドのロジックは他の場所で宣言されています - これは主に明瞭性/分離の問題ですが、javascriptあなたはあなたの手を上げることができる明快さのあらゆるビットが必要です。

第2は効率です。コンストラクタでメソッドを宣言すると、オブジェクトのインスタンスごとに関数オブジェクトの新しいインスタンスが作成され、これらの各関数にコンストラクタのスコープがバインドされます(つまり、コンストラクタへの引数は、オブジェクトが存続する限りは決してgcできません)。プロトタイプのメソッドを宣言すると、すべてのインスタンスで使用される関数オブジェクトの単一のコピーが存在します。プロトタイプのプロパティはインスタンスにコピーされません。

第3の理由は、Backbone.jsとCoffeeScriptのクラス構成で使用されるプロトタイプチェーンなど、プロトタイプメソッドを使用するときに、さまざまな方法でクラスを「拡張」できることです。

11

両者が異なっている:最初のものは、オブジェクトの各のメソッドを保存する方法第二の溶液に対し、プロトタイプオブジェクトにのみへの参照を格納します。これは、各オブジェクトに余分なポインタが含まれていることを意味し、したがって、それぞれ少しずつメモリを占有します。

オブジェクト単位のメソッドでは、メソッドがコンストラクタ(クロージャ)内の変数を参照できるため、プロトタイプメソッドからアクセスできないデータにアクセスすることができます。最後に、プロトタイプの方法は後から変更することができます

、それはあなたがプロトタイプオブジェクトに実行時にBarkを再定義することができ、およびメソッドは常にを通じて検索されるので、この変更は、(このプロトタイプを持つすべてのオブジェクトのために動作しますですプロトタイプ)。

関連する問題