Opas prototyyppipohjaiseen luokkaperintöön JavaScriptissä

Tietokonekielet tarjoavat usein tavan yhdelle objektille periä
toinen esine. Peritty objekti sisältää kaikki vanhemman objektin ominaisuudet. Lisäksi se määrittelee oman sarjansa ainutlaatuisia ominaisuuksia.

Seuraa minua Twitterissä saadaksesi JavaScript-vinkkejä ja kirjailmoituksia.

JavaScript-objektit käyttävät prototyyppipohjaista perintöä. Sen suunnittelu on loogisesti samankaltainen (mutta erilainen toteutuksessa) luokkaperinnöstä tiukasti olio-ohjelmoiduilla kielillä.

Sitä voidaan kuvata löyhästi sanomalla, että kun menetelmiä tai ominaisuuksia liitetään objektin prototyyppiin, ne tulevat käytettäväksi kyseisessä objektissa ja sen jälkeläisissä. Mutta tämä prosessi tapahtuu usein kulissien takana.

Koodia kirjoitettaessa sinun ei tarvitse edes koskea suoraan prototyypin ominaisuuteen. Suoritettaessa split-menetelmää kutsutaan sitä suoraan merkkijonosta kirjaimella: ”hello” .split (“e”) tai muuttujalta: string.split (“,”);

Kun käytät luokkaa ja laajennat avainsanoja sisäisesti, JavaScript käyttää edelleen prototyyppipohjaista perintöä. Se yksinkertaistaa syntaksia. Ehkä tämän vuoksi on tärkeää ymmärtää, kuinka prototyyppipohjainen perintö toimii. Se on edelleen kielen suunnittelun ytimessä.

Tästä syystä monissa oppaissa näet String.prototype.split kirjoitetun sen sijaan, että String.split. Tämä tarkoittaa, että on olemassa menetelmäjako, jota voidaan käyttää merkkijonotyyppisissä objekteissa, koska se on liitetty kyseisen objektin prototyyppiin.

Objektityyppien loogisen hierarkian luominen

Kissa ja koira ovat perineet lemmikiltä, ​​jotka ovat perineet eläimiltä.

Koiralla ja kissalla on samanlaiset piirteet. Sen sijaan, että luisit kaksi eri luokkaa,
voimme yksinkertaisesti luoda yhden luokan lemmikkieläimet ja periä siitä kissan ja koiran. Mutta itse lemmikkieläinluokka voidaan periä myös eläinluokasta.

Ennen kuin aloitamme

Prototyyppien ymmärtäminen on kuin joen ylittäminen koodauksesta tietokonekieliseen suunnitteluun. Kaksi täysin erilaista osaamisaluetta.

Teknisesti ohjelmiston kirjoittamiseen riittää vain luokan kevyt tuntemus ja avainsanojen laajentaminen. Prototyypin ymmärtäminen on kuin pääseminen kielen suunnittelun tummempiin nurkiin. Ja joskus se voi olla oivaltavaa.

Pelkkä tämä opetusohjelma ei riitä. Olen keskittynyt vain joihinkin tärkeisiin asioihin, jotka toivottavasti opastavat sinua oikeaan suuntaan.

Konepellin alle

Objektin perimisen taustalla on rakenne rakentaa hierarkia
samanlaisia ​​esineitä. Voit myös sanoa, että lapsiobjekti on ”johdettu” vanhemmaltaan.

Kuinka prototyyppiketjut luodaan JavaScriptissä.

Teknisesti tämä näyttää miltä se näyttää. Yritä olla ajattelematta liikaa tätä. Ymmärrä vain, että hierarkian huipulla on Object-objekti. Siksi sen oma prototyyppi osoittaa nollaksi. Sen yläpuolella ei ole mitään muuta.

Prototyyppipohjainen objektien perintö

JavaScript tukee esineiden perintöä prototyyppien avulla. Jokaiseen objektiin on liitetty objektiominaisuus nimeltään prototyyppi.

Työskentely luokan kanssa ja avainsanojen laajentamisen kanssa on helppoa, mutta prototyyppipohjaisen perimisen toiminnan ymmärtäminen ei ole triviaalia. Toivottavasti tämä opetusohjelma nostaa ainakin osan sumusta!

Objektikonstruktoritoiminnot

Toimintoja voidaan käyttää objektien rakentajina. Suunnittelutoiminnon nimi alkaa yleensä isoilla kirjaimilla erottaaksesi säännölliset funktiot. Objektien rakentajia käytetään objektin ilmentymän luomiseen.

Jotkut JavaScriptin sisäisistä esineistä on jo luotu samoja sääntöjä noudattaen. Esimerkiksi Numero, Matriisi ja Merkkijono perivät Objektilta. Kuten aiemmin keskustelimme, tämä tarkoittaa, että kaikki Objektiin liitetyt ominaisuudet tulevat automaattisesti saataville kaikille lapsilleen.

Constructors

Prototyypin ymmärtäminen on mahdotonta ymmärtämättä rakentajan toimintojen anatomiaa.

Joten mitä tapahtuu, kun luomme mukautetun rakennustoiminnon? Kaksi ominaisuutta ilmeisesti ilmestyvät luokan määritelmään: rakentaja ja prototyyppi.konstruktori.

Ne eivät osoita samaan esineeseen. Hajotamme ne:

Oletetaan, että määrittelemme uuden luokan nosturin (joko toiminto- tai luokan avainsanan avulla)

Äskettäin luoma räätälöity rakentaja on nyt kiinnitetty mukautetun Crane-luokan prototyyppiin. Se on linkki, joka osoittaa oman rakentajansa. Se luo pyöreän logiikan. Mutta se on vain yksi palapeli.

Katsotaanpa nyt Crane.constructoria:

Crane.constructor itse osoittaa sen objektityypin, josta se on luotu.
Koska kaikki esineenrakentajat ovat natiivitoimintoja, kohde Crane.constructor viittaa objektin tyyppiin Function, toisin sanoen funktiorakentaja.

Tämä Crane.prototype.constructorin ja Crane.constructorin välinen dynaaminen on se, mikä mahdollistaa prototyypin perimän molekyylitasolla. Sinun on harvoin edes ajateltava tätä kirjoittaessasi JavaScriptiä. Mutta tämä on ehdottomasti haastattelukysymys.

Mennään lyhyesti tähän uudelleen. Crane.prototype.constructor osoittaa omaan konstruktoriinsa. Se on melkein kuin sanomalla "Minä olen minä".

Sama tarkka tapahtuu, kun määrität luokan luokan avainsanalla:

Mutta Crane.constructor -ominaisuus viittaa Function konstruktoriin.

Ja näin linkki luodaan.

Nyt itse nosturiobjekti voi olla toisen esineen "prototyyppi". Ja tuo objekti voi olla toisen esineen prototyyppi. Ja niin edelleen. Ketju voi jatkua ikuisesti.

Sivuhuomautus: ES5-tyylisissä toiminnoissa toiminto itsessään on
rakentaja. Mutta ES6-luokan avainsana sijoittaa konstruktorin sen soveltamisalaan. Tämä on vain syntaattinen ero.

Prototyyppipohjainen perintö

Meidän tulisi aina käyttää luokkaa ja laajentaa avainsanoja objektien luomiseen ja perimiseen. Mutta ne ovat vain kommikääre siihen, mikä kulissien takana tapahtuu.

Vaikka objektien perintöhierarkioiden luominen ES5-tyylisen syntaksin avulla on kauan vanhentunut ja harvoin nähdään ammattimaisten ohjelmistokehittäjien keskuudessa, ymmärtämällä sen saat syvemmän kuvan siitä, miten se todella toimii.

Määritetään uusi esine Lintu ja lisätään 3 ominaisuutta: tyyppi, väri ja munat. Lisäämme myös 3 menetelmää: lentää, kävele ja makaa. Joten kaikki linnut voivat tehdä:

Huomaa, että harkitsin tarkoituksella lay_egg-menetelmän. Muista kuinka me
keskusteli aiemmin, että Bird.prototype osoittaa omaa rakentajaansa?

Olet voinut vaihtoehtoisesti liittää munintamenetelmän suoraan Bird.prototyyppiin seuraavassa esimerkissä esitetyllä tavalla:

Ensi silmäyksellä saattaa kuulostaa siltä, ​​ettei ole mitään eroa menetelmien liittämisessä käyttämällä tätä avainsanaa Linnun sisällä ja vain lisäämällä se suoraan Bird.prototype -ominaisuuteen. Koska se toimii edelleen oikein?

Mutta tämä ei ole täysin totta. En syventy yksityiskohtiin jo toistaiseksi, koska en ymmärrä täysin erottelua täällä. Mutta aion päivittää tätä opetusohjelmaa kerättäessäni lisää käsityksiä aiheesta.

(Prototyyppisten veteraanien kommentit ovat tervetulleita!)

Kaikkia lintuja ei tehdä samanlaisiksi

Kohteen perinnöllisyyden koko tarkoitus on käyttää yhtä yhteistä luokkaa, joka määrittelee kaikki ominaisuudet ja menetelmät, jotka kaikki kyseisen luokan lapset perivät automaattisesti. Tämä lyhentää koodia ja säästää muistia.

(Kuvittele, että samat ominaisuudet ja menetelmät määritetään kaikissa lapsiobjekteissa yksitellen kokonaan. Se vie kaksinkertaisen muistin.)

Luodaan useita erityyppisiä lintuja. Vaikka ne kaikki voivat silti lentää, kävellä ja asettaa munia (koska ne ovat peritty päälintuluokasta), jokainen ainutlaatuinen lintulaji lisää omat menetelmänsä, jotka ovat ainutlaatuisia kyseiselle luokalle. Esimerkiksi vain papukaijat voivat puhua. Ja vain korvet voivat ratkaista arvoituksia. Vain laululintu voi laulaa.

Papukaija
Luomme papukaijan ja perimme sen Birdiltä:

Papukaija on säännöllinen rakentajatoiminto kuten Bird.

Ero on siinä, että kutsumme Birdin rakentajaksi Bird.callilla ja välitämme Papukaijan tässä yhteydessä ennen omien menetelmien liittämistä. Bird.call yksinkertaisesti lisää kaikki sen ominaisuudet ja menetelmät Parrot-laitteeseen. Tämän lisäksi lisäämme myös omaa tapaamme: puhua.

Nyt papukaijat voivat lentää, kävellä, munia ja puhua! Mutta meidän ei koskaan tarvinnut määritellä perhokävely- ja lay_eggs-menetelmiä Parrot-laitteen sisällä.

Korppi
Luomme samalla tavalla Raven ja perimme sen Birdiltä:

Korvat ovat ainutlaatuisia siinä mielessä, että ne voivat ratkaista arvoituksia.

Laululintu
Luotakaamme nyt Songbird ja perimme sen Birdiltä:

Laululinnut voivat laulaa.

Testataan lintuja

Loimme juuri joukon erilaisia ​​lintuja, joilla on ainutlaatuiset kyvyt. Katsotaanpa mitä
he kykenevät! Tähän asti olemme vain määritelleet luokkia ja perustaneet ne
hierarkkinen suhde.

Jotta voimme työskennellä esineiden kanssa, meidän on pilkistettävä ne:

Katsotaan varpunen alkuperäisen Bird-konstruktorin avulla:

Sparrow voi lentää, kävellä ja munia, koska se on peritty linjalta, joka määrittelee kaikki nämä menetelmät.

Mutta varpunen ei voi puhua. Koska se ei ole papukaija.

Luotakoon papukaija Parrot-luokasta:

Koska Papukaija peri Birdiltä, ​​saamme kaikki sen menetelmät. Paraketilla on ainutlaatuinen kyky puhua, mutta se ei voi laulaa! Laulamismenetelmä on käytettävissä vain kappaleissa, jotka ovat tyyppiä Songbird. Peritään kärkiminen Songbird-luokasta:

Lopuksi luodaan korppi ja ratkaista joitain arvoituksia:

Luokan käyttö ja laajentaa avainsanoja

ES5-tyyliset rakentajat voivat olla vähän hankalia.

Onneksi meillä on nyt luokka ja laajennamme avainsanoja suorittaaksemme täsmälleen samalla tavalla kuin edellisessä osassa.

luokka korvaa toiminnon

laajentaa ja super () korvaa Bird.call edellisistä esimerkeistä.

Huomaa, että meidän on käytettävä super (), joka kutsuu pääluokan rakentajaa.

Tämä syntaksi näyttää paljon hallittavalta!

Nyt meidän tarvitsee vain hetkestää kohde:

Yleiskatsaus

Luokan perintö auttaa luomaan objektien hierarkian.

Luokat ovat sovellussuunnittelusi ja arkkitehtuurisi peruskivi. He tekevät koodilla työskentelystä hieman inhimillisemmän.

Bird oli tietysti vain esimerkki. Todellisessa tilanteessa se voi olla mikä tahansa sen perusteella, minkä tyyppisiä sovelluksia yrität rakentaa.

Ajoneuvoluokka voi olla moottoripyörän, auton tai säiliön emoyritys.

Kaloja voidaan periä haille, kultakalalle, haudelle ja niin edelleen.

Perintö auttaa meitä kirjoittamaan puhtaampaa koodia ja käyttämään vanhempaa kohdetta uudelleen muistin säästämiseksi toistuvien esineiden ominaisuus- ja menetelmämääritelmissä.