以下の方法で、プロジェクト用の単純なウィジェットを開発するのにかなりの時間を費やしました。
var project = project || {};
(function() {
project.elements = {
prop1: val1,
prop2: val2
}
project.method1 = function(val) {
// Do this
}
project.method2 = function(val) {
// Do that
}
project.init = function() {
project.method1(project.elements.prop1)
project.method2(project.elements.prop2)
}
})()
project.init();
しかし、私は自分のフォーマットを次のように変更し始めました:
function Project() {
this.elements = {
prop1: val1,
prop2: val2
}
this.method_one(this.elements.prop1);
this.method_two(this.elements.prop2);
}
Project.prototype.method_one = function (val) {
//
};
Project.prototype.method_two = function (val) {
//
};
new Project();
確かに、これらはばかげた例なので、アクセルに巻き込まれないでください。しかし、機能的な違いは何ですか、いつどちらかを選択する必要がありますか?
最初の違いは、次のように要約できます。this
は、クラスのInstanceを指します。 prototype
はDefinitionを指します。
次のクラスがあるとします。
var Flight = function ( number ) { this.number = number; };
したがって、ここではクラスのすべてのインスタンスにthis.number
をアタッチしています。すべてのFlight
に独自のフライト番号が必要なため、これは理にかなっています。
var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );
対照的に、prototype
は、すべてのインスタンスからアクセスできる単一のプロパティを定義します。
フライト番号を取得したい場合は、次のスニペットを記述するだけで、すべてのインスタンスがこの新しくプロトタイプ化されたオブジェクトへのReferenceを取得します。
Flight.prototype.getNumber = function () { return this.number; };
2番目の違いは、JavaScriptがオブジェクトのプロパティを検索する方法についてです。 Object.whatever
を探している場合、JavaScriptはメインObjectオブジェクト(他のすべてが継承したオブジェクト)まで到達します、一致が見つかるとすぐに、それを返すか呼び出します。
しかし、それはプロトタイプ化されたプロパティに対してのみ起こります。したがって、上位層this.whatever
のどこかにある場合、JavaScriptはそれを一致と見なさず、検索を続行します。
それが実際にどのように起こるか見てみましょう。
まず、JavaScriptでは[ほぼ]すべてがObjectsであることに注意してください。これを試して:
typeof null
では、Object
の内側を見てみましょう(最後に大文字のO
と.
があることに注意してください)。 Google Chromeのデベロッパーツールで.
を入力すると、その特定のオブジェクト内で使用可能なプロパティのリストが表示されます。
Object.
次に、Function
に対して同じことを行います。
Function.
name
メソッドに気付くでしょう。起動して起動し、何が起こるか見てみましょう。
Object.name
Function.name
次に、関数を作成します。
var myFunc = function () {};
そして、ここにもname
メソッドがあるかどうかを見てみましょう。
myFunc.name
空の文字列を取得する必要がありますが、それで問題ありません。エラーや例外は発生しません。
それでは、その神のようなObject
に何かを追加して、他の場所でも取得できるかどうか確認してみましょう。
Object.prototype.test = "Okay!";
そして、あなたは行きます:
Object.prototype.test
Function.prototype.test
myFunc.prototype.test
すべてのケースで"Okay!"
が表示されます。
各メソッドの長所と短所については、プロトタイピングを「より効率的な」方法として考えることができます。これは、各オブジェクトのプロパティ全体をコピーするのではなく、すべてのインスタンスで参照を保持するためです。一方、これはTightly Couplingの例であり、実際に理由を正当化できるまでは大きな問題です。 this
はコンテキストに関連するため、かなり複雑です。あなたはインターネットで無料でたくさんの良いリソースを見つけることができます。
とにかく、どちらの方法も言語ツールにすぎず、それはあなたとあなたが解決しようとしている問題に実際に依存し、より適切なものを選択します。
クラスのすべてのインスタンスに関連するプロパティが必要な場合は、this
を使用します。すべてのインスタンスで同じように機能するプロパティが必要な場合は、prototype
を使用します。
更新
サンプルスニペットに関して、最初のものはSingletonの例であるため、オブジェクト本体内でthis
を使用することは理にかなっています。このようにモジュール化することで、例を改善することもできます(また、常にthis
を使用する必要はありません)。
/* Assuming it will run in a web browser */
(function (window) {
window.myApp = {
...
}
})( window );
/* And in other pages ... */
(function (myApp) {
myApp.Module = {
...
}
})( myApp );
/* And if you prefer Encapsulation */
(function (myApp) {
myApp.Module = {
"foo": "Foo",
"bar": function ( string ) {
return string;
},
return {
"foor": foo,
"bar": bar
}
}
})( myApp );
2番目のスニペットはそれほど意味がありません。最初にthis
を使用していて、後でprototype
を使用してハッキングしようとしているため、this
が機能しないため機能しませんprototype
よりも優先されます。そのコードからどのような期待があり、どのように機能していたかはわかりませんが、リファクタリングすることを強くお勧めします。
更新
this
をprototype
に優先して詳しく説明するために、例を示し、それをどのように説明できるかを説明できますが、それをバックアップする外部リソースはありません。
例は非常に簡単です:
var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "Nice try!";
myClass.prototype.bar = "Bar";
var obj = new myClass;
obj.foo; // Still contains "Foo" ...
obj.bar; // Contains "Bar" as expected
説明は、私たちが知っているように、this
はコンテキストに関連しています。したがって、コンテキストが準備できるまで、それは存在しません。コンテキストの準備ができたら?新しいインスタンスが作成されているとき!残りは今すぐ推測してください!つまり、prototype
の定義はありますが、this
が優先されるのは、その時点で作成される新しいインスタンスがすべてであるためです。