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.
prototype
Eigendom?Je zou om de. Moeten geven prototype
eigendom om vier redenen.
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.
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.
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..
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.
Functie()
instantiesAlle 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.
prototype
Onroerend goed is een Voorwerp()
VoorwerpDit 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.
prototype
EigendomHoewel 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
.
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.
prototype
Keten Retourneert de eerste eigenschapsovereenkomst die hij in de ketting vindtNet 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.
prototype
Eigenschap met een nieuw object Verwijdert de standaard constructoreigenschapHet 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
prototype
Krijgt altijd de nieuwste waardenDe 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
prototype
Eigenschap met een nieuw object werkt eerdere exemplaren niet bijJe 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.
prototype
Inheritance As Native ConstructorsHopelijk 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
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
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.