JavaScriptではすべてがオブジェクトですが、オブジェクトにも種類があり、通常のオブジェクト(Object)と関数オブジェクト(Function)の2つに大別されます。
一般に、new Function によって生成されたオブジェクトは Function オブジェクトであり、それ以外のオブジェクトは通常のオブジェクトです。
例:
function f1(){ //todo } var f2 = function(){ //todo }; var f3 = new Function('x','console.log(x)'); var o1 = {}; var o2 = new Object(); var o3 = new f1(); console.log( typeof f1,//function typeof f2,//function typeof f3,//function typeof o1,//object typeof o2,//object typeof o3 //object ); >> function function function object object object
f1 は関数宣言であり、f2 は実際には関数式である f2 に代入されますが、これは一般的ではありません。関数式とも呼ばれます。
Function は JS に付属するオブジェクトです。f1 と f2 が作成されると、JS は new Function() を通じてこれらのオブジェクトを自動的に構築します。したがって、これら 3 つのオブジェクトはすべて new Function() によって作成されます。
Javascript でオブジェクトを作成するには、オブジェクト リテラルと新しい式を使用する 2 つの方法があります。o1 と o2 の作成は、これら 2 つの方法に対応します。Java と C# を使用して理解する場合、o3 はインスタンスです。 f1、o3、および f1 のオブジェクトは同じ型です。少なくとも私はそう思っていましたが、そうではありません...
それでは、非常に簡単です。o3 が生成されるかどうかを確認してください。 new Function は、Function オブジェクトではないため、明らかにそうではありません。通常のオブジェクトです。
関数オブジェクトと通常のオブジェクトを簡単に理解した後、JavaScript のプロトタイプとプロトタイプ チェーンを見てみましょう:
JS では、関数オブジェクト f1 が作成されるたびに、いくつかのプロパティがオブジェクトに組み込まれます。プロトタイプと __proto__ を含むプロトタイプは、f1 のいくつかの属性とメソッドを記録するプロトタイプ オブジェクトです。
プロトタイプは f1 には見えないことに注意してください。つまり、f1 はプロトタイプ内のプロパティとメソッドを検索しません。
function f(){} f.prototype.foo = "abc"; console.log(f.foo); //undefined
それでは、プロトタイプは何に役立つのでしょうか? 実際、プロトタイプの主な機能は継承です。 平たく言えば、プロトタイプで定義されたプロパティとメソッドは、それ自体の「子孫」用に予約されているため、サブクラスはプロトタイプのプロパティとメソッドに完全にアクセスできます。
f1 がプロトタイプを「子孫」に残す方法を知りたい場合は、JS のプロトタイプ チェーンを理解する必要があります。このとき、JS の __proto__ は非常に奇妙に見え、非常に隠されています。あまり見かけませんが、この関数は通常のオブジェクトと関数オブジェクトの両方に存在し、JS が新しい式を通じてオブジェクトを作成するときに、通常は親クラスを保存します。プロトタイプは新しいオブジェクトの __proto__ 属性に割り当てられ、世代から世代への継承を形成します...
function f(){} f.prototype.foo = "abc";var obj = new f(); console.log(obj.foo); //abc
これで、obj の __proto__ が f のプロトタイプを保存し、次に f のプロトタイプに保存されることがわかりました。 __proto__ に保存されていますか? 以下の図を見てください:
図に示すように、f.prototype の __proto__ に保存されているのは Object.prototype であり、Object.prototype オブジェクトにも __proto__ があり、そこから出力されます。 , Object.prototype.__proto__ は null で、obj オブジェクト プロトタイプ チェーンの終わりを示します。以下の図に示すように:
obj オブジェクトがこのようなプロトタイプチェーンを持った後、obj.foo が実行されると、obj は最初にその属性があるかどうかを検索しますが、foo の場合は独自のプロトタイプは検索しません。が見つからない場合、obj はプロトタイプ チェーンに沿って順番に検索します...
上の例では、f のプロトタイプに foo 属性を定義し、obj はプロトタイプ チェーンでこの属性を見つけて実行します。
最後に、この記事に含まれる重要なポイントをいくつかの文で要約します:
プロトタイプ チェーンの形成は、実際には、プロトタイプではなく __proto__ に依存します。JS エンジンがオブジェクトのメソッドを実行するときは、最初にオブジェクト自体を検索します。メソッドが存在するかどうか、存在しない場合はプロトタイプ チェーン上で検索されますが、独自のプロトタイプは検索されません。
オブジェクトの __proto__ は独自のプロトタイプ チェーンを記録し、独自のデータ型を決定します。__proto__ を変更することは、オブジェクトのデータ型を変更することと同じです。
関数のプロトタイプは、それ自体のプロトタイプ チェーンに属しません。これは、サブクラス作成の中核であり、サブクラスのデータ型を決定し、サブクラスのプロトタイプ チェーンを接続するブリッジです。
プロトタイプ オブジェクトのメソッドとプロパティを定義する目的は、サブクラスによって継承され、使用されることです。