プロトタイプチェーンは理解するのが少し混乱しており、オンライン情報がたくさんあります。夜は眠れないたびに、私は常にいくつかのプロトタイプチェーンや閉鎖記事をオンラインで読むのが好きです。これは非常に効果的です。
これらの多くの用語を心配する必要はありません。脳をひねらせることを除いて、本当に助けにはなりません。プロトタイプチェーンを簡単かつ大まかに見て、人間、悪魔、シーメールの男性など、コードとは何の関係もないことを考えてください。
1)人々は人間によって生まれ、モンスターは悪魔によって生まれます。人間と悪魔はどちらもオブジェクトの例であり、人間と悪魔はプロトタイプです。プロトタイプは、プロトタイプオブジェクトと呼ばれるオブジェクトでもあります。
2)人の母親と父親はたくさんの赤ちゃんを産むことができ、悪魔の母親と彼の父親はたくさんの赤ちゃんを出産することができます。男の妻と男はたくさんの赤ちゃんを産むことができます。男性は、一般的に人間として知られているコンストラクターです。
3)人々はセックスに関する情報を記録できるので、人々はセックスを通してセックスに関する情報を見つけることができます。つまり、プロトタイプオブジェクトを介してコンストラクターを見つけることができます。
4)人々は母親の多くの赤ちゃんを出産することができますが、これらの赤ちゃんには1人の母親しかいません。これはプロトタイプの独自性です。
5)人々はまた、人々によって生まれ、人々を通して人々を見つけ、そして人々を通して人々を見つけます...この関係はプロトタイプチェーンと呼ばれます。
6)プロトタイプチェーンは無限ではありません。人を見上げ続けると、人々はクソしていることがわかります...つまり、プロトタイプチェーンが最終的にヌルを指していることがわかります。
7)母親と一緒に生まれた人は人のように見え、母親と一緒に生まれたモンスターは醜いでしょう。これは継承と呼ばれます。
8)あなたはあなたの母親の肌の色を継承しました、あなたの母親はあなたの母親、あなたの母親の肌の色を継承しました...、これはプロトタイプチェーンの相続です。
9)家がない場合、あなたの家はあなたの母親の家を指します。あなたの母親が家を持っていない場合、あなたの家はあなたの母親の家を指します...これはプロトタイプチェーンの上向きの検索です。
10)母親の外観を継承しますが、髪、シャンプー、カット、ブローを染色することもできます。つまり、オブジェクトの属性をカスタマイズし、継承された属性をオーバーライドすることもできます。
11)黄色の髪を洗ったり、切断したり、吹き飛ばしたり、染めたりしましたが、母親の外観を変えることはできません。あなたの母親に生まれた弟と妹は、黄色の髪の洗浄、切断、黄色の髪とは何の関係もありません。つまり、オブジェクトインスタンスはプロトタイプの特性を変更できません。
12)しかし、あなたの家があなたによって焼かれている場合、それはあなたの母親とあなたの兄弟が焼かれていることを意味し、これはプロトタイプの属性の共有です。
13)あなたの母親のニックネームはアゼンであり、彼女の隣人の叔母はあなたをアズヘナーと呼びますが、あなたの母親の髪がピアオロからゴールデンライオンキングに変わった後、隣の叔母は彼女の言葉を変え、あなたをゴールデンライオンの王子と呼びました。これは、プロトタイプの動的な性質と呼ばれます。
14)あなたの母親は美しさを愛し、整形手術のために韓国に行きました。彼女は母親さえ認識できませんでした。たとえあなたの母親の髪が柔らかさに戻っても、隣の隣人はあなたをゴールデンライオンの王子と呼んでいます。誰もあなたの母親を認識していないので、あなたの母親は整形手術後に工場に戻りました。これは、プロトタイプの全体的な書き換えです。
くそ!あなたは十分です! BBではありません!コードを見せて!
function person(name){this.name = name; } function mother(){} mother.prototype = {// mother's prototype age:18、home:['beijing'、 'shanghai']}; person.prototype = new Mother(); //人のプロトタイプは母親です//クロムデバッグツールを使用してプロトタイプを表示し、__Proto__インターフェイスを提供してプロトタイプVAR P1 = New Person( 'Jack')を表示します。 // p1: 'jack'; __proto __:18、['beijing'、 'shanghai'] var p2 = new person( 'mark'); // p2: 'mark'; __proto __:18、['beijing'、 'shanghai'] p1.age = 20; /*インスタンスは、プロトタイプの基本的な値属性を変更することはできません。黄色の髪が母親とは何の関係もないように、P1インスタンスの下に年齢属性を追加する通常の操作は、プロトタイプとは関係ありません。 var o {}と同じ; O.age = 20。 * P1:以下に追加の属性年齢があり、__Proto__はmother.prototype、Age = 18と同じです。 * p2:属性名のみ、__proto__はmother.prototypeと同じです*/p1.home [0] = 'shenzhen'; /*プロトタイプでの参照型属性の共有は、あなたがあなたの家を燃やすように、それはあなたの家族全員の家を燃やしているようなものです*これはちょっとしたパスです、それを下に注意深く悩ませましょうか? * P1:「ジャック」、20; __proto __:18、['Shenzhen'、 'Shanghai']* p2: 'mark'; __proto __:18、['Shenzhen'、 'Shanghai']*/p1.home = ['hangzhou'、 'guangzhou']; /*実際、p1.age = 20と同じ操作。この理解に変更:var o {}; o.house = ['big'、 'house']* p1: 'jack'、20、['hangzhou'、 'guangzhou']; __proto __:18、['Shenzhen'、 'Shanghai']* p2: 'mark'; __proto __:18、['Shenzhen'、 'Shanghai']*/delete p1.age; /*カスタム属性を削除した後、最初に上書きされたプロトタイプ値が再発現されます。これは上向きの検索メカニズムであるため、次のダイナミクス* P1: 'Jack'、['Hangzhou'、 'Guangzhou']があります。 __proto __:18、['Shenzhen'、 'Shanghai']* p2: 'mark'; __proto __:18、['Shenzhen'、 'Shanghai']*/person.prototype.lastname = 'Jin'; /*プロトタイプを書き直し、インスタンスに動的に反応します。あなたの母親がトレンディな人になったように、隣人はあなたがそれを言及するとき、あなたはトレンディな女性の息子であると言います*ここで私たちはここで人のプロトタイプを書き直していることに注意してください。これは母に属性を追加することです。異なるレベルを変更すると、効果は非常に異なることがよくあります。 * p1: 'jack'、['hangzhou'、 'guangzhou']; __proto __: 'jin'; __ proto __:18、['shenzhen'、 'shanghai']* p2: 'mark'; __proto __: 'jin'; __ proto __:18、['shenzhen'、 'shanghai']*/person.prototype = {age:28、address:{country: 'usa'、city: 'washington'}}; var p3 = new person( 'obama'); /*プロトタイプを書き直してください!この時点で、人のプロトタイプは完全に新しいオブジェクトになりました。つまり、人が母親を変えたことを意味します。 *このように理解するには:var a = 10; b = a; a = 20; c = a。したがって、Bは変更されておらず、Cになるため、P3は変化し、母親とは何の関係もありません。 * p1: 'jack'、['hangzhou'、 'guangzhou']; __proto __: 'jin'; __ proto __:18、['shenzhen'、 'shanghai']* p2: 'mark'; __proto __: 'jin'; __ proto __:18、['shenzhen'、 'shanghai']* p3: 'obama'; __ proto __:28 {usa '、city:' washington '}*/mother.prototype.no = 9527;*あなたの母親が新しいトレンドになったように、隣人はあなたが本当にトレンディなおばあちゃんだと言います*私たちはここでプロトタイプを書き直していることに注意してください。P1P2は変わりますが、上記のP3は母親とは何の関係もなく、それは彼に影響しません。 * p1: 'jack'、['hangzhou'、 'guangzhou']; __proto __: 'jin'; __ proto __:18、['shenzhen'、 'shanghai']、9527* p2: 'mark'; __proto __: 'jin'; __ proto __:18、['shenzhen'、 'shanghai']、9527* p3: 'obama'; __Proto__:28 {国: 'USA'、都市:「ワシントン '}*/mother.prototype = {car:2、趣味:[' run '、' walk ']}; var p4 = new person(' tony ');/*プロトタイプのプロトタイプを書き直してください!この時点で、母親のプロトタイプは完全に新しいオブジェクトになりました! *人と母親は上から切断されているため、母親の変化はもはや人に影響を与えません。 * p4: 'tony'; __ proto__:28 {country: 'usa'、city: 'washington'}*/person.prototype = new Mother(); //再びbing bing p5 = new person( 'luffy'); //これらの変更を適用する必要がある場合、人のプロトタイプを母親に再バウンドする必要があります// p5: 'luffy'; __ proto__:2、['run'、 'walk'] p1 .__ proto __.__ proto __.__ protoヌル?マザー.__ proto __.__ proto __.__ proto__ // null、プロトタイプチェーンのエンドポイントはnullではないと思いますか?あなたは基本的にそれを読んだ後に理解することができますか?
次に、p1.age = 20、p1.home = ['hangzhou'、 'guangzhou']とp1.home [0] = 'shenzhen'の違いについて話しましょう。 p1.home [0] = 'Shenzhen';要約すると、p1.object.method、p1.object.propertyなどのフォームです。
p1.age = 20; p1.home = ['hangzhou'、 'guangzhou'];これらの2つの文は理解しやすいです。最初にプロトタイプを忘れて、通常のオブジェクトに属性を追加する方法について考えてください。
var obj = new object(); obj.name = 'xxx'; obj.num = [100、200];
この方法を理解していますか?同じです。
それでは、なぜP1.home [0] = 'Shenzhen'はP1の下でホームアレイプロパティを作成してから、最初の位置を「深Shenzhen」に設定しないのですか?これを忘れて、上記のOBJオブジェクトについて考えてみましょう。このように書かれている場合:var obj.name = 'xxx'、obj.num = [100、200]、必要な結果を得ることができますか?明らかに、エラー以外は何も得られません。 OBJはまだ定義されていないため、どうすれば何かを追加できますか?同様に、P1.home [0]の家はP1で定義されていないため、家を直接定義することは不可能です[0]。 P1の下でホームアレイを作成したい場合は、もちろん次のように書かれています。
p1.home = []; p1.home [0] = 'Shenzhen';
これは最も一般的に使用される方法ではありませんか?
P1.home [0] = 'Shenzhen'がエラーを直接報告しない理由は、プロトタイプチェーンに検索メカニズムがあるためです。 P1.Objectを入力すると、プロトタイプチェーンの検索メカニズムは、最初にインスタンスで対応する値を検索することです。見つからない場合は、プロトタイプで検索されます。見つからない場合、プロトタイプチェーンの以前のレベルで検索します...プロトタイプチェーンの終わりに到達します。つまり、まだ発見されていない場合、未定義を返します。 p1.home [0]を入力すると、同じ検索メカニズムも当てはまります。最初にP1を検索して、自宅という名前の属性とメソッドがあるかどうかを確認し、次に段階的に上方に検索します。最後に、母親のプロトタイプで見つけたので、修正することは母親のプロトタイプの変更と同等です。
要約すると、p1.home [0] = 'shenzhen'はmother.prototype.home [0] = 'shenzhen'に相当します。
上記の分析から、プロトタイプチェーン継承の主な問題は属性の共有にあることがわかります。多くの場合、メソッドのみを共有したいが、属性を共有したいと考えています。理想的には、各インスタンスには独立した属性が必要です。したがって、プロトタイプの継承を改善するには2つの方法があります。
1)組み合わせ継承
function mother(age){this.age = age; this.hobby = ['running'、 'football']} mother.prototype.showage = function(){console.log(this.age); }; function person(name、age){mother.call(this、age); // 2番目の実行this.name = name; } person.prototype = new Mother(); // first execution person.prototype.constructor = person; person.prototype.showname = function(){console.log(this.name);} var p1 = new person( 'jack'、20); p1.hobby.push( 'basketball'); // p1: 'jack'; __proto __:20、['running'、 'football'] var p2 = new person( 'mark'、18); // p2: 'mark'; __proto __:18、['running'、 'football']結果は紫色です:
ここで最初の実行が実行されると、person.prototype.age = undefined、person.prototype.hobby = ['running'、 'football']を取得します。 2番目の実行は、var p1 = new person( 'jack'、20)であり、p1.age = 20、p1.hobby = ['running'、 'football'を取得します。プッシュした後、P1.hobby = ['running'、 'Football'、 'Basketball'になります。実際、これの変化を理解することは比較的簡単です。これを置き換えるだけで、この結果を得ることができます。理解するのが少し混乱していると感じたら、心の概念を捨てて、ブラウザとして上から下にコードを実行してください。出てきますか?
プロトタイプコンストラクターMother()を2度目に実行することにより、プロトタイプインスタンスにプロトタイプのプロパティのコピーをコピーして、プロトタイププロパティと分離して分離できるようにしました。注意している場合は、初めてMother()に電話したときに、役に立たないようです。どうしてそれを呼ぶことができませんか?はい、次の寄生的な組み合わせ継承があります。
2)寄生的な組み合わせ継承
function object(o){function f(){} f.prototype = o; return new f();} function enternitprototype(person、mother){var prototype = object(mother.prototype); prototype.constructor = person; person.prototype = prototype; } function mother(age){this.age = age; this.hobby = ['running'、 'football']} mother.prototype.showage = function(){console.log(this.age); }; function person(name、age){mother.call(this、age); this.name = name; } enselitPrototype(人、母); person.prototype.showname = function(){console.log(this.name);} var p1 = new person( 'jack'、20); p1.hobby.push( 'basketball'); // p1: 'jack'; __proto __:20、['running'、 'football'] var p2 = new person( 'mark'、18); // p2: 'mark'; __proto __:18、['running'、 'football']結果は紫色です:
プロトタイプにはもはや年齢や趣味の属性はありません。2つの方法しかありません。これはまさに私たちが望む結果です!
キーポイントはオブジェクト(o)にあります。ここでは、ここで一時的なオブジェクトがnew Mother()を呼び出すことを巧みに避け、プロトタイプOを使用して新しいオブジェクトインスタンスを返すため、プロトタイプチェーンの設定を完了します。とても混乱していますよね?それは、person.prototype = mother.prototypeを直接設定できないためです。
まとめ
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
多くのことを言って、実際には1つのコアしかありません。属性共有と独立したコントロールです。オブジェクトインスタンスが独立した属性を必要とする場合、すべてのプラクティスの本質は、オブジェクトインスタンスに属性を作成することです。あまり考えない場合は、プロトタイプのプロパティを上書きするために必要な独立した属性を直接定義できます。要するに、プロトタイプの継承を使用する場合、プロトタイプの属性に特に注意を払う必要があります。なぜなら、それらはすべて全身に影響を与える存在であるからです。
以下は、JSでオブジェクトを作成するためのさまざまな方法の簡単なリストです。現在最も一般的に使用されている方法は、コンビネーションモードです。馴染みのある学生は、記事の最後までスキップして、それが好きです。
1)元のモード
// 1。オリジナルモード、オブジェクトリテラルモードvar person = {name: 'jack'、age:18、sayname:function(){alert(this.name); }}; // 1。オリジナルモード、オブジェクトコンストラクターモードvar person = new object(); person.name = 'jack'; person.age = 18; person.sayname = function(){alert(this.name);};明らかに、Person1、Person2のバッチを作成したい場合は、毎回多くのコードを入力する必要があり、シニアコピーパスターでさえ耐えられません!次に、大量生産の工場モデルがあります。
2)工場モデル
// 2。工場モード、オブジェクト関数CreatePerson(name、age)を作成する関数を定義します{var temp = new object(); person.name = name; person.age = age; person.sayname = function(){alert(this.name);}; return temp; }工場モードは大量生産であり、簡単な呼び出し(Papapa ...)で人工モードに入ることができます。あなたの名前と年齢を指定して、たくさんの赤ちゃんを作成し、手を解放できます。ただし、工場で操作されているため、オブジェクトの種類、人間であろうと犬であろうと犬であるかどうかを識別することはできません(テストのInstanceはオブジェクトです)。さらに、人間を作成するたびに、独立した温度オブジェクトを作成する必要があり、コードは肥大化し、蝶はエレガントです。
3)コンストラクター
// 3。コンストラクターモード、オブジェクト関数担当者(name、age)のコンストラクター関数を定義します{this.name = name; this.age = age; this.sayname = function(){alert(this.name);}; } var p1 = new person( 'jack'、18); // P1オブジェクトの人を作成します( 'Jack'、18); //属性メソッドはウィンドウオブジェクトに与えられます。ウィンドウ、window.name = 'jack'、window.sayname()はジャックを出力しますコンストラクターは、C ++とJavaのクラスのコンストラクターに似ており、理解しやすいです。さらに、人はタイプ認識として使用できます(Instanceof Testは人とオブジェクトです)。ただし、すべてのインスタンスはまだ独立しており、インスタンスの異なる方法は実際には異なる機能です。ここで機能という言葉を忘れて、SayNameをオブジェクトとして扱い、それを理解してください。つまり、Zhang SanのSaynameとLi SiのSaynameは存在が異なりますが、明らかに私たちが期待しているのは、メモリを保存するためにSaynameを共有することです。
4)プロトタイプモード
// 4。プロトタイプモード、プロトタイプ属性function person(){} person.prototype.name = 'jack'; person.prototype.age = 18; person.prototype.sayname = function(){alert(this.name); }; // 4。プロトタイプ、リテラル定義メソッドfunction person(){} person.prototype = {name: 'jack'、age:18、sayname:function(){alert(this.name); }}; var p1 = new person(); // name = 'jack'var p2 = new person(); // name = 'jack'ここで注意する必要があるのは、プロトタイプの属性とメソッドの共有です。つまり、すべてのインスタンスはプロトタイプの属性メソッドのみを参照し、任意の場所で生成される変更は他のインスタンスの変更を引き起こします。
5)混合モード(構築 +プロトタイプ)
// 5。プロトタイプ構築コンビネーションモード、function person(name、age){this.name = name; this.age = age;} person.prototype = {hobby:['running'、 'football']; sayname:function(){alert(this.name); }、sayage:function(){alert(this.age); }}; var p1 = new person( 'jack'、20); // p1: 'jack'、20; __Proto__:['running'、 'football']、sayname、sayagevar p2 = new person( 'mark'、18); // p1: 'mark'、18; __ proto__:['running'、 'football']、sayname、sayageアプローチは、コンストラクターに独立する必要があるプロパティ方法を配置することであり、共有できる部分はプロトタイプに配置されます。これにより、オブジェクトインスタンスの独立性を保持しながら、メモリの節約を最大化できます。