JavaScript で「prototype」と「this」のどちらを使うか? 質問する

JavaScript で「prototype」と「this」のどちらを使うか? 質問する

違いは何ですか?

var A = function () {
    this.x = function () {
        //do something
    };
};

そして

var A = function () { };
A.prototype.x = function () {
    //do something
};

ベストアンサー1

これらの例の結果は非常に異なります。

違いを見る前に、次の点に注意してください。

  • コンストラクターのプロトタイプは、インスタンスのプライベート プロパティを介してインスタンス間でメソッドと値を共有する方法を提供します[[Prototype]]
  • 関数のthis は、関数の呼び出し方法またはbindの使用によって設定されます(ここでは説明しません)。関数がオブジェクトに対して呼び出される場合 (例myObj.method())、メソッド内のthis はオブジェクトを参照します。呼び出しまたはbindの使用によってthis が設定されていない場合、デフォルトでグローバル オブジェクト (ブラウザーのウィンドウ) に設定されます。または、厳密モードでは未定義のままになります。
  • JavaScript はオブジェクト指向言語です。つまり、関数を含め、ほとんどの値はオブジェクトです。(文字列、数値、ブール値はオブジェクトではありませ。)

問題となっているスニペットは次のとおりです。

var A = function () {
    this.x = function () {
        //do something
    };
};

この場合、変数にはA関数への参照である値が割り当てられます。その関数が を使用して呼び出されるとA()、関数のthis は呼び出しによって設定されないため、デフォルトでグローバル オブジェクトに設定され、式はthis.xになりますwindow.x。その結果、右側の関数式への参照が に割り当てられますwindow.x

の場合:

var A = function () { };
A.prototype.x = function () {
    //do something
};

まったく異なることが起こります。最初の行では、変数Aに関数への参照が割り当てられます。JavaScript では、すべての関数オブジェクトにデフォルトでprototypeプロパティがあるため、 A.prototypeオブジェクトを作成するための別のコードはありません。

2 行目では、A.prototype.xに関数への参照が割り当てられます。これにより、xプロパティが存在しない場合は作成され、存在する場合は新しい値が割り当てられます。これが、オブジェクトのxプロパティが式に関係する最初の例との違いです。

もう一つの例を以下に示します。これは最初の例と似ています (おそらく、あなたが尋ねたかったのはこの例でしょう)。

var A = new function () {
    this.x = function () {
        //do something
    };
};

この例では、new関数式の前に演算子が追加されているため、関数はコンストラクターとして呼び出されます。 で呼び出されるとnew、関数のthis は[[Prototype]]、プライベートプロパティがコンストラクターのパブリックプロトタイプを参照するように設定されている新しいオブジェクトを参照するように設定されます。そのため、代入ステートメントでは、この新しいオブジェクトにプロパティが作成されます。コンストラクターとして呼び出されると、関数はデフォルトでthisxオブジェクトを返すため、別のステートメントは必要ありません。return this;

Aにxプロパティがあるかどうかを確認するには:

console.log(A.x) // function () {
                 //   //do something
                 // };

これは、コンストラクターを参照する唯一の方法がA.constructor経由であるため、 newの珍しい使用法です。次のようにする方がはるかに一般的です。

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

同様の結果を達成する別の方法は、即時に呼び出される関数式を使用することです。

var A = (function () {
    this.x = function () {
        //do something
    };
}());

この場合、A右側の関数呼び出しの戻り値を に代入します。ここでも、呼び出しではthis がthis.x設定されていないため、グローバル オブジェクトを参照し、が有効になりますwindow.x。関数は何も返さないため、Aの値は になりますundefined

2 つのアプローチの違いは、JavaScript オブジェクトを JSON にシリアル化したり、JSON からデシリアル化したりする場合にも現れます。オブジェクトのプロトタイプで定義されたメソッドは、オブジェクトをシリアル化してもシリアル化されません。これは、たとえばオブジェクトのデータ部分だけをシリアル化し、メソッドはシリアル化したくない場合に便利です。

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

関連する質問:

補足: 2 つのアプローチの間には大きなメモリ節約はないかもしれませんが、プロトタイプを使用してメソッドとプロパティを共有すると、各インスタンスが独自のコピーを持つ場合よりもメモリ使用量が少なくなる可能性があります。

JavaScript は低レベル言語ではありません。プロトタイピングやその他の継承パターンを、メモリの割り当て方法を明示的に変更する方法として考えることは、あまり意味がないかもしれません。

おすすめ記事