プロトタイプとは何ですか
関数タイプにはプロパティプロトタイプがあり、プロトタイプに直接翻訳されています。このプロパティはポインターであり、オブジェクトを指しています。オブジェクトには、現在の関数によって生成されるすべてのインスタンス(オブジェクト)によって共有されるプロパティとメソッドが含まれています。
以前に言われたことに基づいて、次のコードを取得できます。
function person(){...} person.prototype = {country: 'china'、sayname:function(){...}}最初に、関数タイプのインスタンスの人が作成され、次に人のメソッドプロトタイプはオブジェクトであり、宣言はオブジェクトを指します。このオブジェクトのプロパティとメソッドは、現在の個人関数によって生成されたインスタンスによって共有されます。つまり、
person1 = new person(); person2 = new person();
Person1とPerson2はどちらも、人間関数タイプインスタンスを介して再び生成されます。どちらも共通の財産国とメソッドセイナルを持っています。なぜなら、それらはすべてポインター(__Proto__)を持っているため、Person.Prototypeによって指されたオブジェクトを直接指しています。ただし、__Proto__ポインターは標準ではないことに注意してください。 ChromeやFirefoxなどのブラウザによってのみ定義されます。実際、このプロパティは使用されませんが、プロトタイプの理解としてのみ使用されます。
プロトタイプやその他の方法の使用については、後で具体的に説明します。
オブジェクトパターンを作成します
次に、オブジェクトを作成するための方法と一般的なパターン、およびその利点と短所を見てみましょう。
1。工場モデル
工場のように、具体的なオブジェクトを作成するプロセスが抽象化され、関数を使用して、特定のインターフェイスを持つオブジェクトの作成の詳細をカプセル化します。部分的な繰り返し作業の代わりに関数を使用することにより、コードは次のとおりです。
function createperson(name、age、job){var o = new object(); o.name = name; o.age = age; o.job = job; o.sayname = function(){alert(this.name); }; return o;} var person1 = createperson( "jiangshui"、 "22"、 "Engineer");これにより、人が作成され、工場パターンは複数の類似のオブジェクトを繰り返し作成する問題を解決しますが、オブジェクト認識の問題は解決しません。オブジェクトが単純に作成されているだけであり、このオブジェクトが人間のテンプレートまたは動物テンプレートから作成されていても、このオブジェクトのタイプを区別することは不可能です。
2。コンストラクターモード
カスタムオブジェクトタイプのプロパティと方法を定義するカスタムコンストラクターを作成します。
function person(name、age、job){this.name = name; this.age = age; this.job = jpb; this.sayname = function(){alert(this.name); };}; var person1 = new person(...);3.コンストラクターモードと工場モードの違い:
人は関数タイプのオブジェクトです。新しい後、オブジェクトは引き続き生成されます。ただし、この新しく生成されたオブジェクトは関数に渡され、このポインターに割り当てられているため、渡されたコンテンツは、新しく生成されたオブジェクトのプロパティまたは方法になります。
コンストラクターのデフォルトの習慣は、最初の文字で大文字になります。上記のコード実行は、次の手順を実行します。
この方法で生成されたインスタンスでは、それらはすべて、デフォルトでコンストラクター関数を指すコンストラクター属性を含む。たとえば、:
alert(person1.constructor == person);
したがって、コンストラクターパターンを使用すると、タイプの区別があり、そのインスタンスは特定のタイプとして識別できます。
さらに、コンストラクターは通常の機能です。あなたは新しいオブジェクトを取得するためにフィードバックをしたいので、あなたはそれを呼ぶために新しいオブジェクトを使用します。そうでない場合は、直接実行することは通常の関数のようなものです。たとえば、上記のperson.sayname()を実行すると、window.nameがウィンドウの下で実行されるためにポップアップされるため、このポイントはウィンドウになります。
コンストラクターモードにも欠陥があります。コンストラクターモードのメソッドは各インスタンスで再作成されるため、異なるインスタンスで同じ名前の関数は等しくありません。例えば:
person1.sayname == person2.sayname; //間違い
つまり、コンストラクターによって生成された各オブジェクトインスタンス、属性、およびメソッドは一意であり、コピーされます。これはオブジェクト間の違いであるため、属性は一意ですが、多くの方法には同じ機能とコードがあります。それらを何度も繰り返しコピーすると、明らかにリソースを無駄にします。
そのため、関数を外に置いてから、コンストラクターにポインターを使用して関数を指すことができます。生成されたインスタンスでは、メソッドは特定の関数へのポインターを保存します。これは、共有関数を意味します。
function person(name、age){this.name = name; this.age = age; this.sayname = sayname;} function sayname(){alert(this.name);}ただし、このようにして、この関数はグローバルな関数になり、個人コンストラクターと高度に相関しておらず、カプセル化もありません。
次に、プロトタイプモードをご覧ください。
プロトタイプモード
プロトタイプに関する基本の一部が以前に導入されました。簡単に言えば、各関数にはプロトタイプ属性があり、オブジェクト(プロトタイプオブジェクト)を指し、いくつかのプロパティまたはメソッドをこのオブジェクトに配置できます。次に、この関数によって生成されたインスタンスには、プロトタイプを指す不規則な属性(__Proto__)があります。
この観点から、プロトタイプによって生成された特性と方法がすべてのインスタンスで共有されていることを理解できるはずです。
これは、上記のコンストラクターモードと例で関数を共有する問題を解決するだけです。たとえば、次のコード:
function person(....} person.prototype.name = "jiangshui"; person.prototype.sayname = function(){alert(this.name);}; var person1 = new person(); person1.sayname(); // jiangshuiまたは
person.prototype = {constructor:person、name: "jiangshui"、sayname:function(){alert(this.name); }};2番目のメソッドはプロトタイプオブジェクト全体をカバーするため、コンストラクター機能を指すコンストラクタープロパティを手動で指定する必要があります。それ以外の場合は、オブジェクトを指します。
彼らの関係を整理しましょう:
isprototypeof()を使用して、オブジェクト間の関係を決定します。例えば:
person.prototype.isprototypeof(person1);
コードがオブジェクトの特定のプロパティを読み取ると、検索が実行されます。現在のオブジェクトから始めて、そうでない場合は、コンストラクターを検索せずに、ポインターによって指されたプロトタイプオブジェクトを検索します。オブジェクトインスタンスにアクセスできますが、プロトタイプオブジェクトの値をオーバーライドすることはできません。プロトタイプオブジェクトと同じ名前の属性がインスタンスで設定されている場合、検索プロセスはプロトタイプオブジェクトにアクセスせずにインスタンスで終了するため、上書きの目的が達成されます。したがって、このプロパティがnullに設定されていても、プロパティがインスタンスに既に存在し、プロパティがキャンセルされないことを意味するため、プロトタイプの対応するプロパティにアクセスできます。
したがって、プロトタイプを再検討できるように、削除演算子を使用してインスタンス属性を完全に削除する必要があります。
プロトタイプは動的であり、プロトタイプオブジェクトに加えられた変更は、インスタンスからすぐに反映できます。その理由は、インスタンスとプロトタイプの間のゆるいリンク関係です。インスタンスのプロパティ方法が呼び出されるたびに、クエリが実行されます。プロトタイプが変更された場合、クエリの結果も変更されます。
プロトタイプを理解した後、新しいメソッドまたは属性をネイティブオブジェクトに追加することもできます。オブジェクト、配列、文字列などのネイティブリファレンスタイプは、上記のコンストラクターに似ています。プロトタイプを使用してメソッドを拡張できます。例えば:
string.prototype.startswith = function(text){return this.indexof(text)== 0;}; var msg = "hello world"; msg.startswith( "hello");このコードは、ネイティブ参照タイプの文字列にStartSwithメソッドを追加します。これは、パラメーターに渡して、テストする文字列がパラメーターで始まるかどうかを確認するためです。プロトタイプの動的な性質により、文字列型のすべての変数は、実行してこの方法を取得します。
ただし、この方法は推奨されません。コードが多すぎて多くのコードを使用すると、メンテナンスの難しさ、コードの混乱などが発生します。一般的に、ネイティブの参照タイプが最初に継承され、次に新しくカスタマイズされたタイプで作成されます。継承に関しては、後で要約します。
プロトタイプパターンも全能ではありません。プロトタイプ内のすべての属性とメソッドはすべてのインスタンスで共有されるため、関数やその他の機能には非常に適していますが、参照タイプを含む属性については、一部の競合が発生します。例えば:
function person()person.pers.prototype = {constructor:person、friends:["greg"、 "jack"]}; var person1 = new person(); new person2 = new person(); person1.friends.push( "tom"); console.log(person2.friends);コンソールでは、Person2の友人のための余分なTOMがあることがわかります。
そのため、プロトタイプパターンとコンストラクターパターンと組み合わせて使用する必要があります。
コンストラクターモードとプロトタイプモードを組み合わせて使用します
これは最も一般的に使用されるパターンです。コンストラクターは、インスタンスプロパティを定義し、パラメーターを渡すことでカスタマイズするために使用されます。プロトタイプは、すべてのインスタンス間で共有する必要があるメソッドまたは属性を定義するために使用されます。このようにして、カスタマイズが達成され、共有が確保され、問題が回避されます。
function person(name、age、job){this.name = name; this.age = age; this.job = job; this.friends = ["greg"、 "jack"];} person.prototype = {constructor:person、sayname:function(){alert(this.name); }}; var jiangshui = new person( "Jiangshui"、 "22"、 "Engineer");実用的なアプリケーションの例
OK、ここでは、プロトタイプとは何か、オブジェクトを作成する方法を理解できますが、これらの使用は何ですか?確かに、私の以前の作業はjQueryを使用してコードを作成することであり、カプセル化を使用してから、機能を実装するオブジェクトを生成することができませんでした。
この開発方法は、主にモジュラー開発およびアセンブリ開発に使用されます。たとえば、よく使用するポップアップ関数は、もちろん毎回ポップアップコードを貼り付けてコピーしてから、プロジェクトで変更して使用できます。より良い選択は、ポップアップ関数コードをそのようなコンポーネントに抽象的にカプセル化することです。そのため、ポップアップを使用する必要がある場合は、ポップアップインスタンスを生成するためにパラメーターを渡すだけで、呼び出すことができます。
プロトタイプオブジェクトとプロトタイプチェーン
JavaScriptでは、すべてがオブジェクトですが、オブジェクトにも違いがあります。これは、通常のオブジェクト(オブジェクト)と関数オブジェクト(関数)の2つのカテゴリにほぼ分割できます。
一般的に、新しい関数を介して生成されるオブジェクトは関数オブジェクトであり、他のオブジェクトは通常のオブジェクトです。
例を挙げてください:
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 objectof o3 // object); >>関数関数オブジェクトオブジェクトオブジェクトF1は関数の宣言に属します。関数を定義する最も一般的な方法は、F2が実際に匿名関数であることです。この匿名関数を関数式に属するF2に割り当てます。 F3は一般的ではありませんが、関数オブジェクトでもあります。
関数はJSに付属のオブジェクトです。 F1とF2が作成されると、JSは新しい関数()を介してこれらのオブジェクトを自動的に構築します。したがって、これらの3つのオブジェクトは、new function()を使用して作成されます。
JavaScriptにオブジェクトを作成するには、オブジェクトリテラルと新しい式の2つの方法があります。 O1とO2の作成は、これら2つの方法にちなんで対応しています。 O3に焦点を当てましょう。 JavaとC#のアイデアを使用して理解する場合、O3はF1のインスタンスオブジェクトであり、O3とF1は同じタイプです。少なくとも私は以前にそう思っていましたが、そうではありません...
それで、あなたはそれをどのように理解しますか?とても簡単です。 O3が新しい関数によって生成されるかどうかを確認します。明らかにそうではありません。関数オブジェクトではないため、通常のオブジェクトです。
関数オブジェクトと通常のオブジェクトを簡単に理解した後、JavaScriptのプロトタイプとプロトタイプチェーンについて学びましょう。
JSでは、関数オブジェクトF1が作成されるたびに、プロトタイプや__Proto__を含む一部のプロパティがオブジェクトに組み込まれています。プロトタイプはプロトタイプオブジェクトであり、F1のプロパティとメソッドを記録します。
プロトタイプはF1には見えないことに注意する必要があります。つまり、F1はプロトタイプの特性と方法を探しません。
関数f(){} f.prototype.foo = "abc"; console.log(f.foo); //未定義では、プロトタイプの使用は何ですか?実際、プロトタイプの主な機能は継承です。素人の用語では、プロトタイプで定義されているプロパティと方法はすべて「子孫」に任されているため、サブクラスはプロトタイプのプロパティと方法に完全にアクセスできます。
F1が「子孫」のプロトタイプをどのように残すかを知るには、JSのプロトタイプチェーンを理解する必要があります。現時点では、JSの__Proto__が市場に参入しています。この男は非常に奇妙で隠されているので、しばしば見ないようにしますが、通常のオブジェクトと関数オブジェクトの両方に存在します。その機能は、親クラスのプロトタイプオブジェクトを保存することです。 JSが新しい式を介してオブジェクトを作成すると、通常、親クラスのプロトタイプを新しいオブジェクトの__Proto__属性に割り当てます。
関数f(){} f.prototype.foo = "abc"; var obj = new f(); console.log(obj.foo); // ABCこれで、OBJの__Proto__がFのプロトタイプを保存することがわかっているので、Fのプロトタイプの__Proto__で何が保存されているのでしょうか?次の写真を参照してください。
図に示されているように、object.prototypeはf.prototypeの__proto__に保存されており、object.prototypeオブジェクトに__proto__もあります。出力結果から、object.prototype .__プロトタイプはnullであり、OBJオブジェクトプロトタイプチェーンの終わりを示しています。下の図に示すように:
OBJオブジェクトにそのようなプロトタイプチェーンがある後、OBJ.FOOが実行されると、OBJは最初に属性があるかどうかを見つけますが、独自のプロトタイプは見つかりません。 Fooが見つからない場合、OBJはプロトタイプチェーンに沿って順番に検索します...
上記の例では、FのプロトタイプのFOO属性を定義し、OBJはプロトタイプチェーンでこの属性を見つけて実行します。