通常、プロトタイプ関数は次のようにクラス定義の外部で宣言されます。
function Container(param) {
this.member = param;
}
Container.prototype.stamp = function (string) {
return this.member + string;
}
var container1 = new Container('A');
alert(container1.member);
alert(container1.stamp('X'));
このコードは、値「A」と「AX」を持つ 2 つのアラートを生成します。
クラス定義の内側にプロトタイプ関数を定義したいと思います。このようにしても問題はありませんか?
function Container(param) {
this.member = param;
if (!Container.prototype.stamp) {
Container.prototype.stamp = function() {
return this.member + string;
}
}
}
私はクラス内のプライベート変数にアクセスできるようにこれを試していました。しかし、プロトタイプ関数がプライベート変数を参照する場合、プライベート変数の値は、オブジェクトインスタンスの値ではなく、プロトタイプ関数が最初に作成されたときに使用された値であることがわかりました。
Container = function(param) {
this.member = param;
var privateVar = param;
if (!Container.prototype.stamp) {
Container.prototype.stamp = function(string) {
return privateVar + this.member + string;
}
}
}
var container1 = new Container('A');
var container2 = new Container('B');
alert(container1.stamp('X'));
alert(container2.stamp('X'));
このコードは、値「AAX」と「ABX」を持つ 2 つのアラートを生成します。出力が「AAX」と「BBX」になることを期待していました。なぜこれが機能しないのか、また代わりに使用できる他のパターンがあるかどうかが知りたいです。
編集:この単純な例では、プロトタイプをまったく使用せずに、 のようなクロージャをthis.stamp = function() {}
使用するのが最善であることは十分に理解しています。私もそうします。しかし、プロトタイプを使用して詳細を学習する実験を行っており、いくつかのことを知りたいと思います。
- クロージャの代わりにプロトタイプ関数を使用する意味があるのはどのような場合ですか? 既存のオブジェクトを拡張するためにのみ使用する必要があります
Date
。閉鎖はより速い。 - 何らかの理由でプロトタイプ関数を使用する必要がある場合、私の例のようにクラス内で定義しても「OK」ですか、それともクラス外で定義する必要がありますか?
- 各インスタンスの privateVar 値がプロトタイプ関数にアクセスできず、最初のインスタンスの値にのみアクセスできる理由を理解したいと思います。
ベストアンサー1
クロージャの代わりにプロトタイプ関数を使用するのはどのような場合に適していますか?
まあ、これは最も軽量な方法です。あるコンストラクタにメソッドがありprototype
、1000個のオブジェクトインスタンスを作成すると、それらのすべてのオブジェクトのプロトタイプチェーンにメソッドがあり、それらはすべて1つの関数オブジェクト。
コンストラクター内でそのメソッドを初期化すると ( this.method = function () {};
)、1000 個のオブジェクト インスタンスすべてが関数オブジェクトを独自のプロパティとして持つことになります。
何らかの理由でプロトタイプ関数を使用する必要がある場合、私の例のようにクラス内で定義しても「OK」ですか、それともクラス外で定義する必要がありますか?
コンストラクターのプロトタイプのメンバーをそれ自体の中で定義することはあまり意味がありません。これについて、またコードが機能しない理由について、さらに詳しく説明します。
各インスタンスの privateVar 値がプロトタイプ関数にアクセスできず、最初のインスタンスの値にのみアクセスできる理由を理解したいと思います。
コードを見てみましょう:
var Container = function(param) {
this.member = param;
var privateVar = param;
if (!Container.prototype.stamp) { // <-- executed on the first call only
Container.prototype.stamp = function(string) {
return privateVar + this.member + string;
}
}
}
コードの動作に関する重要な点は、Container.prototype.stamp
関数創造された最初のメソッド呼び出し時。
関数オブジェクトを作成すると、現在の囲みスコープが と呼ばれる内部プロパティに保存されます[[Scope]]
。
var
このスコープは、後で関数を呼び出すときに、または FunctionDeclarationを使用して関数内で宣言された識別子 (変数) によって拡張されます。
[[Scope]]
プロパティのリストは、スコープチェーン、識別子(privateVar
変数など)にアクセスすると、それらのオブジェクトが検査されます。
また、関数は最初のメソッド呼び出し ( new Container('A')
) で作成されたため、privateVar
この最初の関数呼び出しのスコープにバインドされ、メソッドをどのように呼び出しても、そのスコープにバインドされたままになります。
これを見て答え最初の部分はステートメントについてですwith
が、2 番目の部分では関数のスコープ チェーンがどのように機能するかについて説明します。