De prototype
Egenskapen er et objekt som er opprettet av JavaScript for hver Funksjon()
forekomst. Spesifikt kobler den objektobjekter som er opprettet med ny
søkeord tilbake til konstruktørfunksjonen som opprettet dem. Dette er gjort slik at forekomster kan dele eller arve, vanlige metoder og egenskaper. Det er viktig at delingen skjer under eiendomsoppslag. Husk fra den første artikkelen at hver gang du ser opp eller får tilgang til en eiendom på et objekt, blir eiendommen søkt på objektet, så vel som prototypekjeden.
Et prototypobjekt opprettes for hver funksjon, uavhengig av om du har tenkt å bruke denne funksjonen som en konstruktør.
I den følgende koden konstruerer jeg en matrise fra Array ()
konstruktør, og deretter påkaller jeg bli med()
metode.
Eksempel: sample118.html
De bli med()
Metoden er ikke definert som en egenskap av myArray
objekt-forekomst, men på en eller annen måte har vi tilgang til bli med()
som om det var. Denne metoden er definert et sted, men hvor? Vel, det er definert som en eiendom av Array ()
konstruktørens prototypeegenskap. Siden bli med()
finnes ikke i arrayobjektet, ser JavaScript opp prototypekjeden for en metode som kalles bli med()
.
Ok, så hvorfor er ting gjort på denne måten? Egentlig handler det om effektivitet og gjenbruk. Hvorfor bør alle array-forekomster opprettet fra array constructor-funksjonen ha en unikt definert bli med()
metode når bli med()
Fungerer alltid på samme måte? Det er mer fornuftig for alle arrays å utnytte det samme bli med()
funksjon uten å måtte opprette en ny forekomst av funksjonen for hver array-forekomst.
Denne effektiviteten vi snakker om er alt mulig på grunn av prototype
eiendom, prototype kobling og prototype oppslagskjeden. I denne artikkelen bryter vi ned disse ofte forvirrende egenskapene til prototypisk arv. Men sannheten blir fortalt, du ville bli bedre ved å bare huske mekanikken til hvordan kjeden hierarkiet egentlig fungerer. Henvis til den første artikkelen hvis du trenger en oppdatering på hvordan eiendomsverdiene er løst.
prototype
Eiendom?Du burde bryr deg om prototype
eiendom av fire grunner.
Den første grunnen er at prototypegenskapen brukes av de opprinnelige konstruktørfunksjonene (Gjenstand()
, Array ()
, Funksjon()
, etc.) for å tillate konstruktørinstanser å arve egenskaper og metoder. Det er mekanismen som JavaScript selv bruker for å tillate objektet forekomster å arve egenskaper og metoder fra konstruktørfunksjonens prototype
eiendom. Hvis du vil forstå JavaScript bedre, må du forstå hvordan JavaScript selv utnytter prototype
gjenstand.
Når du oppretter brukerdefinerte konstruktørfunksjoner, kan du orkestre arv på samme måte som JavaScript-innfødte objekter gjør. Men først må du lære hvordan det fungerer.
Du kan virkelig ikke likne prototypisk arv eller foretrekker et annet mønster for gjenstand for arv, men virkeligheten er at en dag må du kanskje redigere eller administrere andres kode som trodde prototypal arv var bienes knær. Når dette skjer, bør du være oppmerksom på hvordan prototypisk arv fungerer, samt hvordan den kan replikeres av utviklere som bruker tilpassede konstruktørfunksjoner.
Ved å bruke prototypal arv, kan du opprette effektive objektfelter som alle bruker de samme metodene. Som allerede nevnt, ikke alle array objekter, som er forekomster av Array ()
konstruktør, trenger sin egen bli med()
metoder. Alle forekomster kan utnytte det samme bli med()
metode fordi metoden er lagret i prototypekjeden.
Funksjon()
forekomsterAlle funksjoner er opprettet fra a Funksjon()
konstruktør, selv om du ikke direkte påkaller Funksjon()
konstruktør (var add = ny funksjon ('x', 'y', 'return x + z');
) og i stedet bruk bokstavelig notasjon (var add = funksjon (x, y) retur x + z;
).
Når en funksjonsinstans er opprettet, blir den alltid gitt a prototype
eiendom, som er en tom gjenstand. I den følgende prøven definerer vi en funksjon som heter myFunction og åpner deretter prototype
eiendom som er rett og slett en tom gjenstand.
Eksempel: sample119.html
Pass på at du helt forstår at prototypegenskapen kommer fra Funksjon()
konstruktør. Det er bare en gang vi har tenkt å bruke vår funksjon som en brukerdefinert konstruktørfunksjon som prototypegenskapen er leveransert, men dette endrer ikke det faktum at Funksjon()
Konstruktøren gir hver instans en prototypegenskap.
prototype
Eiendommen er en Gjenstand()
GjenstandAlt dette prototype
snakk kan bli litt tungt. Sannelig, prototype
er bare en tom objektegenskap kalt "prototype" opprettet bak kulissene ved JavaScript og gjort tilgjengelig ved å påkalle Funksjon()
konstruktør. Hvis du skulle gjøre det manuelt, ville det se slik ut:
Eksempel: sample120.html
Faktisk fungerer denne prøvekoden egentlig fint, egentlig bare duplisere hva JavaScript allerede gjør.
Verdien av en prototypegenskap kan settes til noen av de komplekse verdiene (objekter) som er tilgjengelige i JavaScript. JavaScript vil ignorere noen prototypegenskaper satt til en primitiv verdi.
prototype
EiendomMens det bare er et objekt, prototype
er spesielt fordi prototypekjeden kobler hver forekomst til sin konstruktørfunksjons prototypeegenskap. Dette betyr at når et objekt opprettes fra en konstruktørfunksjon ved hjelp av ny
søkeord (eller når et objektomslag er opprettet for en primitiv verdi), legger den til en skjult lenke mellom objektet forekomst opprettet og prototypegenskapen til konstruktørfunksjonen som ble brukt til å lage den. Denne lenken er kjent innenfor forekomsten som __proto__
(selv om det bare er utsatt / støttet via kode i Firefox 2+, Safari, Chrome og Android). JavaScript slår sammen dette i bakgrunnen når en konstruktørfunksjon er påkalt, og den er denne lenken som gjør at prototypekjeden kan være, vel, en kjede. I den følgende prøven legger vi en eiendom til den innfødte Array ()
konstruktører prototype
, som vi kan få tilgang til fra en Array ()
eksempel ved bruk av __proto__
eiendom sett på den forekomsten.
Eksempel: sample121.html
Siden tilgang __proto__
er ikke en del av den offisielle ECMA-standarden, det er en mer universell måte å spore linken fra en gjenstand til prototypen objektet den arver, og det er ved å bruke konstruktør
eiendom. Dette er demonstrert i følgende prøve.
Eksempel: sample122.html
I dette eksemplet er foo
Egenskapen er funnet innenfor prototypeobjektet. Du må innse at dette kun er mulig på grunn av sammenhengen mellom forekomsten av Array ()
og Array ()
konstruktør prototype objekt (Array.prototype
). For å si det enkelt, myArray .__ proto__
(eller myArray.constructor.prototype
) referanser Array.prototype
.
prototype
Kjeden er Object.prototype
Siden prototypegenskapen er en gjenstand, er siste stopp i prototypekjeden eller oppslaget på Object.prototype
. I koden som følger oppretter jeg myArray
, som er en tom rekkefølge. Jeg forsøker da å få tilgang til en eiendom på myArray
som ennå ikke er definert, engasjerer prototype oppslagskjeden. De myArray
objektet undersøkes for foo-eiendommen. Å være fraværende, er eiendommen søkt etter Array.prototype
, men det er heller ikke der. Så det siste stedet JavaScript ser ut er Object.prototype
. Fordi det ikke er definert i noen av de tre objektene, er eiendommen udefinert
.
Eksempel: sample123.html
Legg merke til at kjeden stoppet med Object.prototype
. Det siste stedet vi så etter foo var Object.prototype
.
Forsiktig! Alt som er lagt til Object.prototype vil dukke opp i en for-i-loop.
prototype
Kjede returnerer den første eiendomsmatchen den finner i kjedenSom omfanget kjeden, den prototype
kjeden vil bruke den første verdien den finner under kjedeoppslaget.
Endre forrige kodeeksempel, hvis vi la samme verdi til Object.prototype
og Array.prototype
objekter, og forsøkte å få tilgang til en verdi på en array-forekomst, ville verdien returnert være fra Array.prototype
gjenstand.
Eksempel: sample124.html
I denne prøven er foo verdien på Array.prototype.foo
er skygging, eller maskering, foo
verdi funnet på Object.prototype.foo
. Bare husk at oppslaget slutter når eiendommen er funnet i kjeden, selv om samme eiendomsnavn også brukes lenger opp i kjeden.
prototype
Egenskap med et nytt objekt fjerner standardkonstruksjonsegenskapenDet er mulig å erstatte standardverdien av a prototype
eiendom med en ny verdi. Det vil imidlertid eliminere standardkonstruktøregenskapen som finnes i "pre-made" prototype
objekt med mindre du spesifiserer en manuelt.
I koden som følger oppretter vi en foo
konstruktør funksjon, erstatte prototype
eiendom med en ny tom objekt, og verifiser at byggherreegenskapen er ødelagt (det refererer nå til de mindre nyttige Gjenstand
prototype).
Eksempel: sample125.html
Hvis du har tenkt å erstatte standard prototype
eiendom (vanlig med noen JS OOP-mønstre) satt opp av JavaScript, bør du koble sammen en byggherre som refererer til konstruktørfunksjonen. I den følgende prøven endrer vi vår tidligere kode slik at konstruktør
Egenskapen vil igjen gi en referanse til den riktige konstruktørfunksjonen.
Eksempel: sample126.html
prototype
Vil alltid få de nyeste verdienePrototypegenskapen er dynamisk i den forstand at forekomster alltid vil få den nyeste verdien fra prototypen, uansett når den ble instansiert, endret eller vedlagt. I koden som følger oppretter vi en foo
byggherre, legg til eiendommen x
til prototype
, og opprett deretter en forekomst av Foo ()
oppkalt FooInstance
. Deretter logger vi verdien av x
. Da oppdaterer vi prototypeværdien til x og logger den igjen for å finne ut at vår forekomst har tilgang til den nyeste verdien som finnes i prototype
gjenstand.
Eksempel: sample127.html
Gitt hvordan oppslagskjeden virker, bør denne oppførselen ikke være så overraskende. Hvis du lurer på, fungerer dette det samme uansett om du bruker standardinnstillingen prototype
objekt eller overstyr det med din egen. I neste prøve erstatter jeg standardinnstillingen prototype
protestere mot å demonstrere dette faktum.
Eksempel: sample128.html
prototype
Eiendom med nytt objekt oppdager ikke tidligere forekomsterDu tror kanskje at du kan erstatte prototype
eiendom helt til enhver tid, og at alle forekomster vil bli oppdatert, men dette er ikke riktig. Når du oppretter en forekomst, blir den forekomsten knyttet til prototype
Det ble myntet på tidspunktet for instantiering. Å oppgi et nytt objekt som prototypegenskapen, oppdaterer ikke forbindelsen mellom forekomster som allerede er opprettet og den nye prototype
.
Men husk, som jeg tidligere nevnte, kan du oppdatere eller legge til til opprinnelig opprettet prototype
objekt og disse verdiene forblir koblet til første instans (er).
Eksempel: sample129.html
Nøkkel ideen å ta bort her er at en prototype av objekter ikke skal erstattes med et nytt objekt når du begynner å lage forekomster. Å gjøre det vil resultere i tilfeller som har en lenke til forskjellige prototyper.
prototype
Arv som innfødte byggereForhåpentligvis på dette punktet i artikkelen, synker det i hvordan JavaScript selv utnytter prototype
eiendom for arv (Array.prototype
). Det samme mønsteret kan utnyttes når du lager ikke-innfødte, brukerdefinerte konstruktørfunksjoner. I den følgende prøven tar vi den klassiske Person
objekt og etterligne mønsteret som JavaScript bruker for arv.
Eksempel: sample130.html
I denne koden, a Person()
Konstruktørfunksjonen er opprettet. Vi legger da til egenskaper til prototype
tilhører Person()
, som kan arves av alle tilfeller. Du kan tydeligvis utnytte prototypekjeden i koden din på samme måte som JavaScript utnytter den til opprinnelige objektarv.
Som et godt eksempel på hvordan du kan utnytte dette, kan du opprette en konstruktørfunksjon hvis forekomster arver ben
og våpen
egenskaper hvis de ikke er oppgitt som parametere. I følgende eksempel, hvis Person()
Konstruktøren sendes parametere, parametrene brukes som eksempelegenskaper, men hvis en eller flere parametere ikke er oppgitt, er det en tilbakebetaling. Disse forekomstegenskapene skygger eller maskerer de arvede egenskaper, og gir deg det beste fra begge verdener.
Eksempel: prøve131.html
Prototypal arv ble uttalt for å tillate arvskett som etterligner arvsmønstrene som finnes i tradisjonelle objektorienterte programmeringsspråk. For at et objekt skal arve fra et annet objekt i JavaScript, er alt du trenger å gjøre, å instantiere en forekomst av objektet du vil arve fra, og tilordne det til prototype
Egenskapen til objektet som gjør arven.
I koden prøven som følger, Chef
objekter (cody
) arve fra Person()
. Dette betyr at hvis en eiendom ikke finnes i en Chef
objekt, vil det bli etterspurt på prototypen av funksjonen som ble opprettet Person()
objekter. Å koble opp arven, alt du trenger å gjøre er å instansere en forekomst av Person()
som verdien for Chef.prototype
(Chef.prototype = ny person ();
).
Eksempel: sample132.html
Alt vi gjorde i denne prøven, utnytte et system som allerede var på plass med de opprinnelige objektene. Tenk på det Person()
er ikke ulikt standard Gjenstand()
verdi for prototypegenskaper. Med andre ord, dette er akkurat hva som skjer når en prototype-egenskap, som inneholder standard tomt Gjenstand()
verdi, ser til prototypen av konstruktørfunksjonen som er opprettet (Object.prototype
) for arvede egenskaper.