18

コンストラクターとプロトタイプオブジェクトのメソッドの設定の違いを説明していただけますか?次のコードは、メソッドを設定するこれら2つの方法を示していますsay_hellosay_byeどちらも正常に機能します。

function MessageClass() {
  this.say_bye = function() { alert('see ya'); };
}

MessageClass.prototype.say_hello = function() { alert('hello'); };

x = new MessageClass();
x.say_hello();
x.say_bye();
4

3 に答える 3

31

foxxtrotとannakataはどちらも正しいですが、2セントを投入します。

プロトタイプを使用する場合、「MessageClass」の各インスタンスは実際には同じ関数を参照しています。関数はメモリに1回だけ存在し、すべてのインスタンスで使用されます。プロトタイプではなくコンストラクターでメソッドを宣言する(または特定のインスタンスに追加する)と、MessageClassのインスタンスごとに新しい関数が作成されます。

そうは言っても、ほとんどの場合、目立ったパフォーマンスの違いはおそらくなく、メモリ使用量の違いも見られないでしょう。やむを得ない理由がない限り、私はプロトタイプ方式を採用します。コンストラクターでメソッドを宣言したいと思うかもしれない唯一の理由は、クロージャーが必要な場合です。たとえば、イベントハンドラーがある場合、またはゲッター/セッターを使用してプライベートプロパティをシミュレートする場合は、次のようにします。

function MessageClass() {
    var self = this;
    this.clickHander = function(e) { self.someoneClickedMe = true; };

    var _private = 0;
    this.getPrivate = function() { return _private; };
    this.setPrivate = function(val) { _private = val; };
}

編集:これがコンストラクターで割り当てられた関数を持つ別のオブジェクトによって拡張されたオブジェクトにどのように影響するかについての議論があったので、私はもう少し詳細を追加しています。議論を単純化するために「クラス」という用語を使用するかもしれませんが、jsはクラスをサポートしていないことに注意することが重要です(つまり、適切なオブジェクト指向開発を行うことができないという意味ではありません)。

ほとんどのjavascriptライブラリは、基本クラスとサブクラスでコンストラクタを呼び出します。(例:Prototype.jsのObject.extend)これは、それぞれのコンストラクターで割り当てられたメソッドが、結果のオブジェクトで使用できることを意味します。ただし、自分でオブジェクトを拡張している場合は、予期しない結果が生じる可能性があります。

上記のMessageClassを取得して拡張すると、次のようになります。

function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();

errorMsg = new ErrorMessageClass();

次に、errorMsgにはgetPrivateメソッドとsetPrivateメソッドがありますが、期待どおりに動作しない可能性があります。これらの関数は割り当てられたときにスコープが設定されていたため(つまり、「ErrorMessageClass.prototype = new MessageClass()」では、get / setPrivateメソッドが共有されるだけでなく、_private変数もErrorMessageClassのすべてのインスタンスで共有されます。これにより、基本的に_privateはErrorMessageClassの静的プロパティ。例:

var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'

同様に、clickHandler関数とsomeoneClickedMeプロパティを使用します。

errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'

ただし、this._privateを使用するようにこれらの関数定義を変更してください。

this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };

ErrorMessageClassのインスタンスの動作は、予想どおりになります。

errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'
于 2009-01-07T22:55:50.367 に答える
6

プロトタイプJSでメソッドをバインドする場合は、一度だけ実行する必要があり、オブジェクトクラスにバインドします(これにより、OO JS拡張機能に適格になります)。

「クラス」関数内でバインディングを行う場合、JSはすべてのインスタンスを作成して割り当てる作業を行う必要があります。

于 2009-01-07T22:41:27.493 に答える
5

違いは、メッセージクラスからクラスを派生させる場合です。プロトタイプで宣言されたメソッドのみが、Messageの子クラスで使用可能になります。

于 2009-01-07T22:36:57.517 に答える