Class öröklés egy módja annak, hogy az egyik osztály kiterjeszteni egy másik osztály.

így új funkciókat hozhatunk létre a meglévő tetején.

A “kiterjed” kulcsszó

mondjuk az osztály Animal:

Itt van, hogyan tudjuk képviselni animal objektumot, majd a Animal class grafikusan:

…szeretnénk, hogy létrehoz egy class Rabbit.,

mivel a nyulak állatok, osztály kell alapulnia Animal, hozzáférhetnek az állati módszerek, így a nyulak meg tudják csinálni, amit a “generikus” állatok tehet.

egy másik osztály kiterjesztésének szintaxisa: class Child extends Parent.

hozzunk létre class Rabbit, amely a Animal:

Rabbit osztály mind a Rabbit módszerekhez, például rabbit.hide(), valamint Animal módszerek, például rabbit.run().,

belsőleg, extends kulcsszó működik a jó öreg prototípus mechanika. Rabbit.prototype.] Animal.prototype. Tehát, ha egy módszer nem található a Rabbit.prototype – ban, a JavaScript a Animal.prototype – ből veszi.,

például a rabbit.run módszer megtalálásához a motor ellenőrzi (alulról felfelé a képen):

amint a fejezetből emlékeztetünk natív prototípusok, maga a JavaScript prototípus örökséget használ a beépített objektumokhoz. Pl. Date.prototype.] is Object.prototype. Ezért a dátumok hozzáférhetnek az Általános objektummódszerekhez.,

bármely kifejezés megengedett a extends

osztály szintaxis lehetővé teszi, hogy adja meg nem csak egy osztály, de minden kifejezés után.

például egy függvény hívását generál a szülő osztály:

function f(phrase) { return class { sayHi() { alert(phrase); } };}class User extends f("Hello") {}new User().sayHi(); // Hello

Itt class User örökli az az eredménye, hogy a f("Hello").,

Ez hasznos lehet a fejlett programozási mintákhoz, amikor függvényeket használunk osztályok generálására, sok feltételtől függően, és örökölhetnek tőlük.

egy metódus felülbírálása

most lépjünk előre és felülírjuk a metódust. Alapértelmezés szerint minden olyan módszer, amely nincs megadva a class Rabbit – ban, közvetlenül “a class Animal – ból származik.,

De ha adja meg a saját módszer a Rabbit, mint stop() akkor lesz használva helyette:

class Rabbit extends Animal { stop() { // ...now this will be used for rabbit.stop() // instead of stop() from class Animal }}

Általában nem akarjuk, hogy teljesen cserélje ki egy szülő módszer, hanem inkább az, hogy építeni a tetején, hogy a csípés, vagy bővíteni a funkcionalitást. Teszünk valamit a módszerünkben, de hívjuk a szülő módszert előtte / utána vagy a folyamatban.

osztályok "super" kulcsszó, hogy.

  • super.method(...) szülő módszer hívásához.,
  • super(...) egy szülő konstruktor hívásához (csak a konstruktorunkon belül).

például hagyjuk, hogy a nyúl autohid amikor megállt:

most van a módszer, amely felhívja a szülősuper.stop() a folyamat.

felülbíráló konstruktor

a konstruktorok kap egy kicsit trükkös.

mostanáig, Rabbit nem volt saját constructor.,

specifikáció Szerint, ha egy osztály kiterjeszti egy másik osztály pedig nem constructor, akkor a következő az “üres” constructor keletkezik:

class Rabbit extends Animal { // generated for extending classes without own constructors constructor(...args) { super(...args); }}

Mint láthatjuk, alapvetően felhívja a szülő constructor halad az érveket. Ez akkor történik, ha nem írunk saját konstruktort.

most adjunk hozzá egy egyéni konstruktort a Rabbit – hoz. A earLength name:

, Hiba történt. Most nem hozhatunk létre nyulakat. Mi történt rosszul?

a rövid válasz:

  • az öröklő osztályok Konstruktorainak super(...), és (!) a thishasználata előtt tegye meg.

… de miért? Mi folyik itt? Valójában a követelmény furcsanak tűnik.

természetesen van magyarázat. Nézzünk bele a részletekbe, hogy tényleg megértsd, mi folyik itt.

A JavaScriptben különbséget lehet tenni az öröklő osztály (ún. “származtatott konstruktor”) és más függvények konstruktorfüggvénye között., A származtatott konstruktornak van egy speciális belső tulajdonsága ]:"derived". Ez egy különleges belső címke.

Ez a címke befolyásolja a viselkedését new.

  • ha egy szabályos függvény new segítségével kerül végrehajtásra, akkor egy üres objektumot hoz létre, és this – hoz rendeli.
  • de ha egy származtatott konstruktor fut, akkor ezt nem teszi meg. Elvárja, hogy a szülő konstruktor ezt a munkát.,

tehát egy származtatott konstruktornak meg kell hívnia a super – t a szülő (alap) konstruktor végrehajtásához, különben a this objektum nem jön létre. És hibát követünk el.

a Rabbit kivitelező dolgozni kell hívni super(), mielőtt a this, mint itt:

Nyomós osztály mezőket: egy trükkös megjegyzés:

Speciális megjegyzés

Ez a megjegyzés feltételezi, hogy egy bizonyos tapasztalatok osztályok, talán más programozási nyelvek.,

jobb betekintést nyújt a nyelvbe, valamint elmagyarázza azt a viselkedést is, amely a hibák forrása lehet (de nem túl gyakran).

Ha nehezen érthető, csak folytassa, folytassa az olvasást, majd térjen vissza egy kicsit később.

nem csak a módszereket, hanem az osztálymezőket is felülbírálhatjuk.

bár, van egy trükkös viselkedés, amikor elérjük a felülbírált mező szülő konstruktor, egészen más, mint a legtöbb más programozási nyelvek.,

Tekintsük ezt a példát:

itt, class extends Animal és felülírja name mezőt saját értékével.

nincs saját konstruktor a – ban, így a Animal konstruktor neve.

ami érdekes, hogy mindkét esetben: new Animal() és new Rabbit(), a alert a (*) animal.,

más szóval, a szülő konstruktor mindig a saját mező értékét használja, nem pedig a felülírottat.

mi a furcsa benne?

Ha még nem világos, kérjük, hasonlítsa össze a módszereket.

itt ugyanaz a kód, de athis.name mező helyettthis.showName() módszer:

megjegyzés: most a kimenet más.

és természetesen erre számítunk. Amikor a szülő konstruktort a származtatott osztályba hívják, akkor a felülbírált módszert használja.

… de az osztálymezők esetében ez nem így van. Mint mondta, a szülő konstruktor mindig a szülő mezőt használja.,

miért van különbség?

Nos, az ok a mező inicializálási sorrendjében van. Az osztály mező inicializálva van:

  • az alaposztály konstruktora előtt (ez nem terjed ki semmire),
  • közvetlenül a super() után a származtatott osztályhoz.

esetünkben A származtatott osztály. Nincs benne constructor() . Mint korábban említettük, ez ugyanaz, mintha egy üres konstruktor lenne, csak super(...args).,

So, new Rabbit() hívások super(), így végrehajtva a szülő konstruktort, és (a származtatott osztályok szabálya szerint) csak azt követően, hogy az osztálymezők inicializálásra kerülnek. A szülő konstruktor végrehajtásakor még nincsenek Rabbitosztálymezők, ezért használják a Animal mezőket.

Ez a finom különbség mezők és módszerek specifikus JavaScript

szerencsére, ez a viselkedés csak akkor derül ki, ha egy felülbírált mező használják a szülő konstruktor., Akkor lehet, hogy nehéz megérteni, mi folyik itt, ezért itt magyarázzuk meg.

ha problémává válik, akkor a mezők helyett módszerekkel vagy getterekkel/setterekkel lehet kijavítani.

Super: internals,]

speciális információk

ha először olvassa el a bemutatót-ez a szakasz kihagyható.

az öröklés mögötti belső mechanizmusokról és super.

let ‘ s get a little deeper under the hood of super. Látni fogunk néhány érdekes dolgot az út mentén.,

először is, mindaz, amit eddig megtanultunk, lehetetlen super egyáltalán dolgozni!

igen, valóban, kérdezzük meg magunktól, hogyan kell technikailag működnie? Ha egy objektum metódus fut, akkor az aktuális objektumot this – ként kapja meg. Ha super.method() – nak hívjuk, akkor a motornak a method – t kell beszereznie az aktuális objektum prototípusából. De hogyan?

a feladat egyszerűnek tűnhet, de nem az., A motor ismeri az aktuális objektumot this, így megkaphatja a szülőt methodas this.__proto__.method. Sajnos egy ilyen “naiv” megoldás nem fog működni.

mutassuk be a problémát. Osztályok nélkül, egyszerű tárgyak használata az egyszerűség kedvéért.

ezt a részt kihagyhatja, és a] alszakaszra léphet, ha nem szeretné tudni a részleteket. Az nem fog ártani. Vagy olvassa el, ha érdekli a dolgok mélyreható megértése.

az alábbi példában rabbit.__proto__ = animal., Most próbáljuk meg: a rabbit.eat() fogjuk hívni animal.eat(), a this.__proto__:

a (*) vesszük eat a prototípusból (animal), majd az aktuális objektum összefüggésében hívja. Kérjük, vegye figyelembe, hogy a.call(this) itt fontos, mert egy egyszerűthis.__proto__.eat() végrehajtja a szülőteat a prototípus összefüggésében, nem az aktuális objektum.,

és a fenti kódban valóban rendeltetésszerűen működik: megvan a helyes alert.

most adjunk hozzá még egy objektumot a lánchoz. Meglátjuk, hogyan törnek a dolgok:

a kód már nem működik! Láthatjuk a hibát próbál hívni longEar.eat().

lehet, hogy nem olyan nyilvánvaló, de ha nyomon követjük a longEar.eat() hívást, akkor láthatjuk, miért. Mindkét sorban (*) és (**) a this értéke az aktuális objektum (longEar)., Ez elengedhetetlen: minden objektummódszer az aktuális objektumot this – ként kapja meg, nem prototípus vagy valami.

itt van a kép arról, hogy mi történik:

a problémát önmagában athishasználatával nem lehet megoldani.

]

a megoldás biztosításához a JavaScript még egy speciális belső tulajdonságot ad a funkciókhoz: ].,

Ha egy függvény osztály vagy objektum metódusként van megadva, akkor a] tulajdonság lesz az objektum.

majd super a szülő prototípusának és módszereinek megoldására használja.

lássuk, hogyan működik, először egyszerű objektumokkal:

A módszerek nem ” ingyenesek “

mint korábban ismert, általában a funkciók” ingyenesek”, nem kötődnek a JavaScript objektumaihoz. Így lehet másolni az objektumok között, és hívni egy másik this.,

a] létezése sérti ezt az elvet, mert a módszerek emlékeznek tárgyaikra. ] nem lehet megváltoztatni, így ez a kötés örökre.

az egyetlen hely a nyelvben, ahol] használják – super. Tehát, ha egy módszer nem használ super, akkor továbbra is szabadnak tekinthetjük, és másolhatjuk az objektumok között. De a super a dolgok rosszul fordulhatnak.,

itt van a demo egy rosszsuper eredmény másolás után:

a hívástree.sayHi() mutatja “állat vagyok”. Határozottan rossz.

az ok egyszerű:

itt van a diagram, hogy mi történik:

div>

módszerek, nem függvénytulajdonságok

a különbség nem feltétlenül szükséges számunkra, de fontos a JavaScript számára.

az alábbi példában egy nem metódus szintaxist használunk összehasonlításra., ] a tulajdonság nincs beállítva, és az örökség nem működik:

összefoglaló

  1. egy osztály kiterjesztéséhez: class Child extends Parent:
    • ez azt jelenti, hogy Child.prototype.__proto__ Parent.prototype, így a módszerek öröklődnek.
  2. amikor felülírja a konstruktor:
    • meg kell hívni szülő konstruktor, mint super() in Child konstruktor használata előtt this.,
  3. ha felülír egy másik módszer:
    • tudjuk használni super.method() a Child módszer hívja Parent módszer.
  4. Internals:
    • Methods remember their class/object in the internal ] property. Így oldja meg asuper szülői módszereket.
    • tehát nem biztonságos másolni egy módszert a super egyik objektumról a másikra.,

is:

  • a Nyílfüggvényeknek nincs saját this vagy super, így átláthatóan illeszkednek a környező környezetbe.

Vélemény, hozzászólás?

Az email címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük