Functie Prototype Eigendom

De prototype eigenschap is een object gemaakt door JavaScript voor elke Functie() aanleg. In het bijzonder worden objectexemplaren gekoppeld die zijn gemaakt met de nieuwe sleutelwoord terug naar de constructorfunctie die ze heeft gemaakt. Dit wordt gedaan zodat exemplaren veelgebruikte methoden en eigenschappen kunnen delen of erfen. Belangrijk is dat het delen plaatsvindt tijdens het opzoeken van eigendommen. Onthoud uit het eerste artikel dat elke keer dat u opzoekt of toegang krijgt tot een eigenschap op een object, naar de eigenschap zal worden gezocht op zowel het object als de prototypeketen.

Voor elke functie wordt een prototype gemaakt, ongeacht of u die functie als constructor wilt gebruiken.

In de volgende code maak ik een array van de Array () constructor, en dan roep ik de join () methode.

Voorbeeld: sample118.html

 

De join () methode is niet gedefinieerd als een eigenschap van de myArray object instantie, maar op de een of andere manier hebben we toegang tot join () Alsof het was. Deze methode is ergens gedefinieerd, maar waar? Nou, het is gedefinieerd als een eigenschap van de Array () prototype-eigenschap van de constructor. Sinds join () wordt niet gevonden in de array-objectinstantie, JavaScript zoekt de prototypeketen op voor een methode die wordt genoemd join ().

Oké, dus waarom worden dingen op deze manier gedaan? Het gaat echt om efficiëntie en hergebruik. Waarom zou elke array-instance die is gemaakt met de array-constructorfunctie een unieke definitie hebben join () methode wanneer join () functioneert altijd op dezelfde manier? Het is logischer om alle arrays hetzelfde te laten gebruiken join () functie zonder een nieuw exemplaar van de functie voor elke array-instantie te hoeven maken.

Deze efficiëntie waar we het over hebben is allemaal mogelijk vanwege de prototype eigendom, prototype-koppeling en de prototype-opzoekketen. In dit artikel breken we deze vaak verwarrende attributen van prototypische overerving af. Maar eerlijk gezegd, zou je beter af zijn door simpelweg de mechaniek te onthouden van hoe de ketenhiërarchie echt werkt. Verwijs terug naar het eerste artikel als u opfrissing nodig heeft over hoe vastgoedwaarden worden opgelost.


Waarom zorg over het prototype Eigendom?

Je zou om de. Moeten geven prototype eigendom om vier redenen.

Reden 1

De eerste reden is dat de eigenschap prototype wordt gebruikt door de native constructorfuncties (Voorwerp(), Array (), Functie(), enz.) om toe te staan ​​dat constructorinstanties eigenschappen en methoden erven. Dit is het mechanisme dat JavaScript zelf gebruikt om objectexemplaren eigenschappen en methoden van de constructorfuncties te laten erven prototype eigendom. Als u JavaScript beter wilt begrijpen, moet u weten hoe JavaScript zelf de prototype voorwerp.

Reden 2

Wanneer u door de gebruiker gedefinieerde constructorfuncties maakt, kunt u overerving orkestreren op dezelfde manier als JavaScript-native objecten. Maar eerst moet je leren hoe het werkt.

Reden 3

Je hebt misschien een hekel aan prototypische erfenis of liever een ander patroon voor het overerven van objecten, maar de realiteit is dat je op een dag de code van iemand anders moet bewerken of beheren die dacht dat prototypische erfenis de knieën van de bij was. Wanneer dit gebeurt, moet u zich bewust zijn van hoe prototypische overerving werkt, evenals hoe het kan worden gerepliceerd door ontwikkelaars die gebruik maken van aangepaste constructorfuncties..

Reden 4

Door overerving van prototypes te gebruiken, kunt u efficiënte objectexemplaren maken die allemaal gebruikmaken van dezelfde methoden. Zoals al eerder vermeld, zijn niet alle array-objecten, exemplaren van de Array () constructeur, hebben ze nodig join () methoden. Alle instanties kunnen hetzelfde gebruiken join () methode omdat de methode wordt opgeslagen in de prototypeketen.

Prototype is standaard voor iedereen Functie() instanties

Alle functies zijn gemaakt vanaf a Functie() constructor, zelfs als u niet rechtstreeks een beroep doet op de Functie() constructor (var add = new Function ('x', 'y', 'return x + z');) en gebruik in plaats daarvan de letterlijke notatie (var add = function (x, y) return x + z;).

Wanneer een functie-instantie wordt gemaakt, wordt deze altijd een prototype eigenschap, wat een leeg object is. In het volgende voorbeeld definiëren we een functie met de naam myFunction en openen we de prototype eigenschap die eenvoudigweg een leeg object is.

Voorbeeld: sample119.html

 

Zorg ervoor dat u volledig begrijpt dat de prototype-eigenschap afkomstig is van de Functie() constructeur. Pas als we onze functie als een door de gebruiker gedefinieerde constructorfunctie willen gebruiken, wordt de prototype-eigenschap gebruikt, maar dit verandert niets aan het feit dat de Functie() constructor geeft elke instantie een prototype-eigenschap.


De standaard prototype Onroerend goed is een Voorwerp() Voorwerp

Dit allemaal prototype praten kan een beetje zwaar worden. Werkelijk, prototype is gewoon een lege objecteigenschap genaamd "prototype" achter de schermen gemaakt door JavaScript en beschikbaar gemaakt door het aanroepen van de Functie() constructeur. Als je het handmatig zou doen, zou het er ongeveer zo uitzien:

Voorbeeld: sample120.html

 

In feite werkt deze voorbeeldcode eigenlijk prima, in feite gewoon dupliceren wat JavaScript al doet.

De waarde van een prototype-eigenschap kan worden ingesteld op een van de complexe waarden (objecten) die beschikbaar zijn in JavaScript. JavaScript negeert elke prototype-eigenschap die is ingesteld op een primitieve waarde.


Instanties gemaakt met een Constructorfunctie zijn gekoppeld aan de Constructor prototype Eigendom

Hoewel het slechts een object is, prototype is speciaal omdat de prototypeketen elk exemplaar linkt met de prototype-eigenschap van de constructorfunctie. Dit betekent dat elke keer dat een object wordt gemaakt van een constructorfunctie met behulp van de nieuwe zoekwoord (of wanneer een objectwrapper is gemaakt voor een primitieve waarde), voegt het een verborgen link toe tussen het gemaakte objectexemplaar en de prototype-eigenschap van de constructorfunctie die is gebruikt om het te maken. Deze link is binnen de instantie bekend als __proto__ (hoewel het alleen wordt weergegeven / ondersteund via code in Firefox 2+, Safari, Chrome en Android). JavaScript koppelt dit samen op de achtergrond wanneer een constructorfunctie wordt aangeroepen, en deze link waarmee de prototypeketen, nou ja, een keten is. In het volgende voorbeeld voegen we een eigenschap toe aan de native Array () constructeurs prototype, die we dan kunnen benaderen vanuit een Array () bijvoorbeeld met behulp van de __proto__ property ingesteld op dat exemplaar.

Voorbeeld: sample121.html

 

Sinds de toegang __proto__ is geen onderdeel van de officiële ECMA-standaard, er is een meer universele manier om de link van een object naar het prototypeobject dat het erft te traceren, en dat is door het gebruik van de bouwer eigendom. Dit wordt aangetoond in het volgende voorbeeld.

Voorbeeld: sample122.html

 

In dit voorbeeld is de foo eigenschap wordt gevonden in het prototypeobject. Je moet je realiseren dat dit alleen mogelijk is vanwege de associatie tussen de instantie van Array () en de Array () constructor prototype object (Array.prototype). Simpel gezegd, myArray .__ proto__ (of myArray.constructor.prototype) referenties Array.prototype.


Last Stop In de prototype Chain Is Object.prototype

Omdat de prototype-eigenschap een object is, is de laatste stop in de prototypeketen of -zoekactie aanwezig Object.prototype. In de volgende code maak ik aan myArray, wat een lege array is. Ik probeer dan toegang te krijgen tot een eigenschap van myArray die nog niet is gedefinieerd, waarbij de prototype-opzoekketen wordt gebruikt. De myArray object wordt onderzocht op de foo-eigenschap. Als u afwezig bent, wordt gezocht naar het onroerend goed Array.prototype, maar het is er ook niet. Dus de laatste plaats waar JavaScript eruit ziet is Object.prototype. Omdat het niet is gedefinieerd in een van deze drie objecten, is de eigenschap dat onbepaald.

Voorbeeld: sample123.html

 

Houd er rekening mee dat de ketting is gestopt met Object.prototype. De laatste plaats waar we foo zochten was Object.prototype.

Voorzichtig! Alles dat aan Object.prototype is toegevoegd, wordt weergegeven in een lus voor in.


De prototype Keten Retourneert de eerste eigenschapsovereenkomst die hij in de ketting vindt

Net als de reikwijdte, de prototype keten gebruikt de eerste waarde die het vindt tijdens de ketenopzoeking.

Wijzigen van het vorige codevoorbeeld, als we dezelfde waarde toevoegen aan de Object.prototype en Array.prototype objecten en vervolgens geprobeerd toegang te krijgen tot een waarde op een arrayinstantie, zou de geretourneerde waarde afkomstig zijn van de Array.prototype voorwerp.

Voorbeeld: sample124.html

 

In dit voorbeeld de foo-waarde op Array.prototype.foo is schaduwen, of maskeren, het foo waarde gevonden op Object.prototype.foo. Onthoud dat de zoekopdracht eindigt wanneer het eigendom in de keten wordt gevonden, zelfs als dezelfde propertynaam ook hoger in de keten wordt gebruikt.


De. Vervangen prototype Eigenschap met een nieuw object Verwijdert de standaard constructoreigenschap

Het is mogelijk om de standaardwaarde van a te vervangen prototype eigenschap met een nieuwe waarde. Als u dit wel doet, wordt de standaard constructor-eigenschap uit de "pre-made" verwijderd prototype object tenzij u dit handmatig opgeeft.

In de volgende code maken we een Foo constructorfunctie, vervang de prototype eigenschap met een nieuw leeg object en controleer of de constructoreigenschap is verbroken (deze verwijst nu naar minder nuttig Voorwerp prototype).

Voorbeeld: sample125.html

 

Als u de standaard wilt vervangen prototype eigenschap (gebruikelijk bij sommige JS OOP-patronen) die zijn ingesteld door JavaScript, moet u een constructoreigenschap die verwijst naar de constructorfunctie weer samenvoegen. In het volgende voorbeeld wijzigen we onze vorige code zodat de bouwer eigenschap zal opnieuw een verwijzing naar de juiste constructorfunctie vormen.

Voorbeeld: sample126.html

 

Instanties die eigenschappen overnemen prototype Krijgt altijd de nieuwste waarden

De prototype-eigenschap is dynamisch in die zin dat exemplaren altijd de nieuwste waarde van het prototype krijgen, ongeacht wanneer deze is geïnstantieerd, gewijzigd of toegevoegd. In de volgende code maken we een Foo constructor, voeg de eigenschap toe X naar de prototype, en maak vervolgens een instantie van Foo () genaamd FooInstance. Vervolgens loggen we de waarde in van X. Vervolgens werken we de prototypeswaarde van x bij en loggen deze opnieuw om te ontdekken dat ons exemplaar toegang heeft tot de nieuwste waarde die is gevonden in de prototype voorwerp.

Voorbeeld: sample127.html

 

Gezien hoe de onderzoeksketen werkt, zou dit gedrag niet zo verrassend mogen zijn. Als je je afvraagt, werkt dit hetzelfde, ongeacht of je de standaard gebruikt prototype object of vervang het met uw eigen. In het volgende voorbeeld vervang ik de standaard prototype bezwaar om dit feit te demonstreren.

Voorbeeld: sample128.html

 

De. Vervangen prototype Eigenschap met een nieuw object werkt eerdere exemplaren niet bij

Je zou kunnen denken dat je de prototype eigenschap volledig op elk moment en dat alle exemplaren worden bijgewerkt, maar dit is niet correct. Wanneer u een instantie maakt, wordt die instantie gekoppeld aan de prototype dat werd geslagen op het moment van instantiatie. Als u een nieuw object als de prototype-eigenschap opgeeft, wordt de verbinding tussen instanties die al zijn gemaakt en de nieuwe niet bijgewerkt prototype.

Maar onthoud, zoals ik eerder al zei, kunt u de oorspronkelijk gemaakte update bijwerken of toevoegen prototype object en die waarden blijven verbonden met de eerste instantie (s).

Voorbeeld: sample129.html

 

Het belangrijkste idee om hier afstand van te nemen, is dat een prototype van een object niet moet worden vervangen door een nieuw object zodra u begint met het maken van instanties. Als u dit wel doet, worden er instanties weergegeven met een link naar verschillende prototypen.

Door de gebruiker gedefinieerde constructeurs kunnen hetzelfde benutten prototype Inheritance As Native Constructors

Hopelijk op dit punt in het artikel zinkt het in hoe JavaScript zelf de prototype eigendom voor overerving (Array.prototype). Ditzelfde patroon kan worden gebruikt bij het maken van niet-eigen, door de gebruiker gedefinieerde constructorfuncties. In het volgende voorbeeld nemen we de klassieker Persoon objecteer en imiteer het patroon dat JavaScript gebruikt voor overerving.

Voorbeeld: sample130.html

 

In deze code, a Persoon() constructorfunctie is gemaakt. Vervolgens voegen we eigenschappen toe aan de prototype eigendom van Persoon(), die door alle instanties kan worden geërfd. Het is duidelijk dat u de prototypeketen in uw code kunt gebruiken op dezelfde manier waarop JavaScript deze gebruikt voor de overname van native objecten.

Als een goed voorbeeld van hoe u dit kunt gebruiken, kunt u een constructorfunctie maken waarvan de instanties de benen en armen eigenschappen als ze niet als parameters worden opgegeven. In het volgende voorbeeld, als de Persoon() constructor is verzonden parameters, de parameters worden gebruikt als instantie-eigenschappen, maar als een of meer parameters niet zijn opgegeven, is er een terugval. Deze instantie-eigenschappen schaduwen of maskeren de overgeërfde eigenschappen en geven u het beste van beide werelden.

Voorbeeld: sample131.html

 

Overervingkettingen maken (de oorspronkelijke intentie)

Prototypische overerving werd bedacht om overervingsketens toe te staan ​​die de overervingspatronen nabootsen die worden aangetroffen in traditionele objectgeoriënteerde programmeertalen. Om één object te erven van een ander object in JavaScript, hoeft u alleen maar een instantie van het object waarvan u wilt erven te instantiëren en dit aan het object toe te wijzen. prototype eigenschap van het object dat de overerving uitvoert.

In het codevoorbeeld dat volgt, Chef voorwerpen (cody) erven van Persoon(). Dit betekent dat als een eigenschap niet wordt gevonden in een Chef object wordt vervolgens gezocht naar het prototype van de functie die is gemaakt Persoon() voorwerpen. Om de overerving te bekabelen, hoeft u alleen maar een instantie van te instantiëren Persoon() als de waarde voor Chef.prototype (Chef.prototype = nieuwe persoon (); ).

Voorbeeld: sample132.html

 

Conclusie

Alles wat we in dit voorbeeld hebben gedaan, was gebruik te maken van een systeem dat al bestond met de oorspronkelijke objecten. Overweeg dat Persoon() is niet anders dan de standaard Voorwerp() waarde voor prototype-eigenschappen. Met andere woorden, dit is precies wat er gebeurt als een prototype-eigenschap, die zijn standaard leeg bevat Voorwerp() waarde, kijkt naar het prototype van de gecreëerde constructorfunctie (Object.prototype) voor overgeërfde eigenschappen.