「単玔なのは難しい。」 コンストラクタヌはオブゞェクトずしお機胜したすプロトタむプ。 オブゞェクト、__ proto__。 コンストラクタヌ= {}、コンストラクタヌ関数ずしおnewオブゞェクト

前回 、次のこずを理解しようずしたした。


今日は、コンストラクタヌ関数ずprototypeプロパティの操䜜、およびそれらが生成するオブゞェクトず__proto__プロパティの操䜜に぀いおお話したいず思いたす。 これは、JSで継承を敎理し、JSで発生するプロセスの䞀郚を理解しようずする堎合にしばしば必芁です。 たた、プロトタむプ継承の䞀郚の理解も提䟛したす。 解析の䟋ずしおすべおの人に明確ではないかもしれたせんが、次のコヌドを芋おみたしょう。

䟋1
function A() {} A.prototype.x = 10; a = new A(); console.log(ax); //10 console.log(ay); //undefined A.prototype.y = 20; console.log(ay); //20 /*     A.prototype.<>           */ 2: function B() {} B.prototype.x = 10; b = new B(); console.log(bx); //10 console.log(by); //undefined B.prototype = {constructor:B, x:10, y:20}; console.log(bx); //10 console.log(by); //undefined /*    B.prototype = {constructor:B, x:10, y:20};         */ b1 = new B(); console.log(b1.x); //10 console.log(b1.y); //20 /*       */ b instanceof B; //false b1 instanceof B //true /*          */ 


コンストラクタヌ関数は、オブゞェクトずしお、プロトタむプです。

順番に始めたしょう。 䞀芋シンプルなコヌド行を考えおみたしょう。
 function A() {} 

最初に蚀えるこずは、「Aずいう名前の関数を宣蚀したした」です。 そうです。 しかし、埮劙な違いがありたす。
1. JSでは、ほずんどすべおがオブゞェクトであるこずを忘れないでください。 刀明したように、関数は䟋倖ではありたせんこれらはリンクでリンクされた2぀のオブゞェクトです。
2.コンストラクタヌ関数ずしお䜿甚できたす。
JavaScriptには䞀般にクラスず呌ばれるものはありたせん。 JavaScriptのクラスは、特定の指定されたプロパティを持぀オブゞェクトを䜜成するコンストラクタヌ関数によっお実行されたす。
䞀般に、JSの関数オブゞェクトはコンストラクタヌになりたすナヌザヌ定矩関数に぀いお話したす。 これらは条件付きで3぀に分割できたすDF関数宣蚀、FE関数匏、Functionコンストラクタヌによっお䜜成された関数。 これらの機胜はすべお独自の特性を持っおいたすそのため、異なるグルヌプに分けられおいたすが、ここでそれらに぀いおは説明したせん。興味がある人は個人的に答えるか、別の機䌚に個別に曞きたす。 ただし、これらにはコンストラクタヌになる共通点が1぀ありたす。内郚[[Construct]]プロパティず[[Call]]プロパティのほか、明瀺的なプロトタむププロパティそれに぀いおです。
新しいオブゞェクトにメモリを割り圓おお初期化するのは、内郚メ゜ッド[[Construct]]です。 ただし、これは関数呌び出しがオブゞェクトの䜜成に぀ながるこずを意味するものではありたせん。もちろんそうではありたせん。 これを行うには、関数を呌び出す前にnew挔算子を呌び出したす。 [[Construct]]メ゜ッドず関連プロセスを起動する新しいものです。
 function A(){} A(); //   var a = new A(); // -.  (a)  - (A) 

3.これは関数宣蚀DFなどず蚀うこずもできたすが、残りはただ重芁ではありたせん。

したがっお、「最初の䟋の最初の行からの」「A」関数は、コンストラクタヌ関数およびパヌトタむムオブゞェクトです。 これはオブゞェクトであるため、プロパティを持぀こずができたす。 そうです。 たた、コンストラクタヌ関数であるため、prototypeプロパティがありたす。 prototypeプロパティは、このコンストラクタヌ関数によっお䜜成されたむンスタンスに移動するプロパティずメ゜ッドを栌玍するオブゞェクトぞの参照です。 これらすべおをグラフィカルに衚瀺しおみたしょう。



デフォルトでは、プロトタむプオブゞェクトは「空」ですたあ、ほずんど空ですが、以䞋でさらに詳しく説明したす。 䞊蚘で、私はこのオブゞェクトにあるすべおのものがむンスタンスに入り、子孫にも利甚可胜になるず蚀いたした。 ぀たり、デフォルトではプロトタむプに䜕も远加されおいない堎合、コンストラクタヌ関数「A」からむンスタンスに䜕も移動したせん。 ぀たり、コヌドを実行するずき
 function A(){} var a = new A(); 

「通垞の」JSで可胜な限りオブゞェクト「a」を取埗したす。
JSにはすでに倚くの組み蟌みコンストラクタヌ関数がありたす。 これは、たずえば、Number、Stringなどです。この䟋から少し脱線しお、組み蟌みコンストラクタヌ関数ず䞀般的なオブゞェクトに぀いお話したしょう。

オブゞェクト__ proto__。

前回の蚘事から、組み蟌みコンストラクタヌNumber、String、たたはBooleanのいずれかを䜿甚しお明瀺的たたは暗黙的にオブゞェクトを䜜成するず、むンスタンスはこのタむプに固有のメ゜ッドにアクセスできるこずがわかりたす。 たずえば、NumberにはtoPrecisionメ゜ッドがありたす。 コンストラクタヌnew Number2によっお䜜成されたオブゞェクトのコン゜ヌルを芋るず、そこにこのメ゜ッドは芋぀かりたせんメ゜ッドはたったく芋぀かりたせん。 圌はどこから来たのですか 芪のプロトタむプオブゞェクトに含たれるのは、圌ず同様のメ゜ッド子孫がアクセスする必芁があるメ゜ッドです。 しかし、むンスタンスはどのようにそれらにアクセスしたすか むンスタンスには__proto__プロパティがありたす-これは芪のプロトタむプオブゞェクトぞの参照です。 メ゜ッドを呌び出すずきにメ゜ッドがむンスタンス自䜓にない堎合、__ proto__リンクは芪プロトタむプオブゞェクトに移動し、そこで怜玢が続行されたす。 実際、これはnullが芋぀かるたで繰り返されたす。
これをすべお描いおみたしょう。



芁玄するず、これたでのずころすべおが耇雑ではないずいうこずができたすプロトタむププロパティに、子孫がアクセスするすべおのメ゜ッドずプロパティが栌玍される特定のオブゞェクトぞのリンクを持぀芪コンストラクタヌ関数がありたす。 そしお実際には、新しい呌び出しによっお䜜成されたずきに、共通のプロパティずメ゜ッドを持぀同じオブゞェクトの芪から__proto__プロパティぞのリンクが枡される子孫がありたす。

統合するために、䟋を考えおみたしょう。
 function A() {} //  - (  «» prototype) A.prototype.x = 10;//    prototype(    )  (x)  10 a = new A(); //     __proto__     prototype  (x==10) console.log(ax); // (x)       (a),     __proto__      prototype. console.log(ay); //   (y)     . A.prototype.y = 20; //   (y)  prototype(     ) console.log(ay); //20 //        __proto__  


コンストラクタヌ。

私は、「空の」プロトタむプず蚀ったずき、垞に「空の」ずいう蚀葉を匕甚笊で囲みたす。 同様に、コンストラクタヌ関数function A{}を䜜成するず、「空の」プロトタむプオブゞェクトを参照しおプロトタむププロパティが䜜成されたす。 そうでもない。 プロトタむプにはただ䜕かがありたす。 第䞀に、プロトタむプは「単玔な」オブゞェクトであるため、Objectコンストラクタヌ関数のプロトタむプぞの参照を持぀__proto__プロパティはそこにありたすすべおの「単玔な」最も基本的なオブゞェクトを䜜成したす。コンストラクタヌプロパティがありたす。 コンストラクタヌは、オブゞェクトだけでなく、コンストラクタヌ関数が䜜成されおいるこずを認識するず、コンストラクタヌプロパティをそこに远加したす最初に、これら2぀の事実を念頭に眮いお最初の描画を補完したしょう。



灰色で描かれおいるものはすべお、今のずころ本圓に必芁ありたせん。これは、より完党な画像を埗るためです。 コンストラクタヌプロパティに泚目したしょう。 図からわかるように、コンストラクタヌは、この「リポゞトリヌ」、぀たりこのオブゞェクトが最初に䜜成されたコンストラクタヌ関数自䜓を指したす。 ぀たり、コンストラクタヌ関数のプロトタむププロパティずプロトタむプオブゞェクトのコンストラクタヌプロパティの間には、埪環性が珟れたす。これらは互いのオブゞェクトを指したす。
コンストラクタヌプロパティを䜿甚しおコンストラクタヌをただポむントし、コンストラクタヌのプロトタむププロパティが元のプロトタむプをポむントしおいる堎合、オブゞェクトプロトタむプぞの参照を間接的に取埗できたすa.constructor.prototype.x。 たた、コンストラクタヌ関数自䜓ず、プロトタむプオブゞェクトではなく、具䜓的に割り圓おられたそのプロパティぞのリンクを取埗できたす。 䟋
 function A(){} A.own = 'I am A!'; //     —        a = new A(); a.own //undefined a.constructor.own // 'I am A!'; 

= {}-コンストラクタヌ関数ずしお新しいオブゞェクト。

玠晎らしい、すべおが適切に萜ちたようです。 「共通ストレヌゞ」があり、芪ず子にはこのストレヌゞぞのリンクがありたす。プロパティがむンスタンス自䜓にない堎合、むンタヌプリタヌはリンクをクリックしお「共通ストレヌゞ」を探したす。 キャッチは䜕ですか?? 䟋2を芋おみたしょう。
 function B() {} B.prototype.x = 10; b = new B(); console.log(bx); //10 console.log(by); //undefined B.prototype = {constructor:B, x:10, y:20}; console.log(bx); //10 console.log(by); //undefined 

すべおが機胜するようです。 コンストラクタヌ関数を䜜成し、「共通ストレヌゞ」プロトタむプリンク経由プロパティxを蚭定し、むンスタンスを䜜成し、プロパティxがありたす-すべお問題ありたせん。 次に、通垞、プロトタむプの芪プロパティを再定矩し、プロパティxずyを远加しお正しいコンストラクタを瀺したした。 すべおがこれらのプロパティの䞡方の「共有リポゞトリ」で動䜜するはずですが、いいえ、yむンタプリタはそれを芋぀けたせん。 WTF

ここではどのような魔法が起こっおいたすか このコンストラクタの子孫からこれらの倉曎が衚瀺されないのはなぜですか 子孫にyが衚瀺されないのはなぜですか たず、最初に、コンストラクタヌ関数Bのプロトタむププロパティをオヌバヌラむドし、新しいオブゞェクトを参照し始めたす元のプロトタむプオブゞェクトずの接続が切断されたす。 第二に、むンタプリタによるvar a = {}などのオブゞェクト倉数の通垞の割り圓おは、実際にはvar a = new Objectずしお実行されたす。 これは、コンストラクタヌ関数のプロトタむププロパティに、コンストラクタヌリンクが欠萜しおいる完党に新しいオブゞェクトが含たれるようになり、芪が倱われないように、コンストラクタヌプロパティを個別に远加しお、芪を割り圓おたす。
たた、先ほど䜜成したむンスタンスには、プロパティyがない叀いプロトタむプオブゞェクトぞのリンク__proto__が含たれおいたす。 ぀たり、䟋1ずは異なり、ここでは「リポゞトリにプロパティを远加」せず、「リポゞトリを再床曞き換える」こずもせず、新しいものを䜜成し、叀いものずの接続を切断したしたが、むンスタンスはそれに぀いお䜕も知らず、叀いものを匕き続き䜿甚したす__proto__をリンクしたす。 次のようになりたす。



黒-これは、B.prototype = {constructorB、x10、y20};の埌に倉曎されおいないものです。
èµ€-䜕が消えた
緑-远加されたもの

instanceofに぀いお少し远加するこずもできたす。 奇劙なこずに、この䟋では、b1はコンストラクタヌ関数Bに属し、bはそうではありたせん。 すべおが非垞に簡単です。 実際には、instanceofは次の条件を満たしおいるこずを探しおいたす-リンク__proto __チェヌンの任意のレベルで指定されたオブゞェクト番号1の円は、目的の芪のプロトタむププロパティによっお参照されたオブゞェクト番号2の円ず同じです図の黒ず比范しおください色ず緑。 黒ではこの条件は満たされなくなり、緑では満たされたす。
私たちの堎合、むンスタンスbでは、目的の芪Bの新しいプロトタむププロパティが以前ではなく新しいオブゞェクトをすでに参照しおいるため、この接続は切断されたす。 しかし、私たちが芋るように、これを持぀むンスタンスb1は敎然ずしおいたす。

埌

これに関しおは、コンストラクタヌ関数の本䜓には觊れたせん。これに぀いおは、次の蚘事で詳しく説明したす。 私が蚀う唯䞀のこずは、newを介しおコンストラクタヌずしお関数を呌び出すずきは、䜜成されるむンスタンスを指し、関数ずしお呌び出すずきはグロヌバルオブゞェクトを指すずいうこずです。
䟋を芋おみたしょう
 function A(str){ this.val = str; } a = new A('test'); //  val   ,        this       A('test'); //  this —   .       val console.log(val) //'test' 


関数がどのように呌び出されたかを調べる方法は 新しいかどうかで これは非垞に簡単に行われたす
 function A(str){ if( this instanceof A) // this   A(    new) this.val = str; //   val else retur str; //(     new)   } 

このようにしお、型倉換のメカニズムが実装されたす。 たずえば、1 + '1'を実行するず、むンタヌプリタヌは+をストリング連結ずしお解釈し、数倀1をストリングにキャストしようずしたす。 これは、String1newなしの暗黙的な呌び出しで発生したす。 たた、Stringのコンストラクタヌには、䞊蚘ず同じ構成に぀いお蚘述されおいたす。 ぀たり、呌び出しがnewなしで発生した堎合、単玔に文字列を返したすtoStringメ゜ッドの暗黙的な呌び出し。 したがっお、オブゞェクトを䜜成せずに、型倉換が発生したす。
たた、プロパティを関数぀たり、プロトタむプではなく関数に远加するには、オブゞェクトずしおアクセスする必芁がありたす。 䟋えば
 function A(){} A.val = 'str'; 

このプロパティはプロトタむプに存圚せず、子孫はそこにのみアクセスできるため、子孫にはアクセスできたせん。 しかし、圌らが「本圓に望むなら、できる」ず蚀うように。 これは、プロトタむプオブゞェクトのプロパティが䟿利な堎所です。 私たちが思い出すように、それは関数自䜓を指したすもちろん、これは特に倉曎されおいない限り。 次に、倉数valを取埗するには、次のようにアクセスする必芁がありたす。
 function A(){} A.val = 'str'; a = new A(); a.constructor.val; //'str' 


゜ヌス
https://developer.mozilla.org
http://dmitrysoshnikov.com/
http://javascript.ru

Source: https://habr.com/ru/post/J151070/


All Articles