třída dědičnost je způsob, jak pro jednu třídu rozšířit jinou třídu.
takže můžeme vytvořit nové funkce na vrcholu stávajících.
„rozšiřuje“ vyhledávání podle klíčových slov
řekněme, že máme třídy Animal
:
Zde je, jak můžeme reprezentovat animal
objekt a Animal
class graficky:
…A my bychom chtěli vytvořit další class Rabbit
.,
Jak králíci jsou zvířata, Rabbit
třída by měla být založena na Animal
, přístup na zvířecí metody, tak, že králíci mohou dělat to, co „generic“ zvířata mohou dělat.
syntaxe pro rozšíření jiné třídy je: class Child extends Parent
.
Pojďme vytvořit class Rabbit
, který se dědí z Animal
:
Objekt Rabbit
třídy mají přístup jak do Rabbit
metody, jako například rabbit.hide()
, a také, aby Animal
metody, jako například rabbit.run()
.,
interně,extends
Klíčové slovo funguje pomocí staré dobré mechaniky prototypu. Nastaví Rabbit.prototype.]
na Animal.prototype
. Pokud tedy metoda není nalezena v Rabbit.prototype
, JavaScript ji vezme z Animal.prototype
.,
například rabbit.run
metoda, motor je v pořádku (dole na obrázku):
Jak můžeme připomenout z kapitoly Nativní prototypy, JavaScript sám používá prototypal dědictví pro vestavěné objekty. Date.prototype.]
je Object.prototype
. Proto mají data přístup k generickým objektovým metodám.,
extends
Třídy syntaxe umožňuje určit nejen třídy, ale každý výraz po extends
.
například, volání funkce, která generuje nadřazené třídy:
function f(phrase) { return class { sayHi() { alert(phrase); } };}class User extends f("Hello") {}new User().sayHi(); // Hello
Zde class User
dědí z výsledku f("Hello")
.,
, které mohou být užitečné pro pokročilé programovací vzory, když používáme funkce pro generování tříd v závislosti na mnoha podmínkách a mohou z nich dědit.
přepsání metody
nyní se pohybujeme vpřed a přepsáme metodu. Ve výchozím nastavení jsou všechny metody, které nejsou specifikovány v class Rabbit
, převzaty přímo „jak je“ z class Animal
.,
Ale pokud máme určit vlastní metody v Rabbit
, např. stop()
pak to bude použit místo:
class Rabbit extends Animal { stop() { // ...now this will be used for rabbit.stop() // instead of stop() from class Animal }}
Obvykle nechceme, aby zcela nahradit mateřské metoda, ale spíše se nám vybudovat na vrcholu, to vylepšit nebo rozšířit jeho funkčnost. Děláme něco v naší metodě, ale zavoláme nadřazenou metodu před/po ní nebo v procesu.
třídy poskytují"super"
Klíčové slovo.
-
super.method(...)
pro volání rodičovské metody., -
super(...)
pro volání nadřazeného konstruktoru (pouze uvnitř našeho konstruktoru).
například, dovolte, náš králík autohide, když se zastavil:
Rabbit
stop
metoda, která volá nadřazený super.stop()
v tomto procesu.
převažující Konstruktor
s konstruktory je to trochu složitější.
dosud Rabbit
neměl vlastní constructor
.,
Podle specifikace v případě, že třída rozšiřuje jinou třídu a nemá žádné constructor
, pak tyto „prázdné“ constructor
je generována:
class Rabbit extends Animal { // generated for extending classes without own constructors constructor(...args) { super(...args); }}
Jak můžeme vidět, je to v podstatě hovory o nadřazený constructor
předáním všechny argumenty. To se stane, když nepíšeme vlastního konstruktéra.
nyní přidáme vlastní Konstruktor do Rabbit
. Bude specifikovat earLength
kromě name
:
Whoops!, Máme chybu. Teď nemůžeme vytvořit králíky. Co se pokazilo?
krátká odpověď zní:
- konstruktéři v dědění tříd musí volat
super(...)
a (!) to před použitímthis
.
… ale proč? Co se to tu děje? Požadavek se zdá být zvláštní.
samozřejmě existuje vysvětlení. Pojďme se dostat do detailů, takže budete opravdu pochopit, co se děje.
v JavaScriptu je rozdíl mezi funkcí konstruktoru zděděné třídy (tzv. „odvozený konstruktor“) a dalšími funkcemi., Odvozený Konstruktor má speciální vnitřní vlastnost ]:"derived"
. To je speciální interní štítek.
tento štítek ovlivňuje jeho chování pomocí new
.
- Při pravidelném funkce je proveden s
new
, to vytvoří prázdný objekt a přiřadí ji dothis
. - ale když běží odvozený Konstruktor, nedělá to. Očekává, že rodič Konstruktor dělat tuto práci.,
odvozené konstruktoru musí být volání super
s cílem vykonávat své mateřské (základní) konstruktor, jinak objekt this
nebude vytvořen. A dostaneme chybu.
na Rabbit
konstruktoru do práce, je třeba volat super()
před použitím this
, jako zde:
Přepsání třídy oblastech: ošemetná poznámka
Tato poznámka se předpokládá, že máte jisté zkušenosti s třídami, možná v jiných programovacích jazycích.,
poskytuje lepší vhled do jazyka a také vysvětluje chování, které by mohlo být zdrojem chyb (ale ne příliš často).
Pokud je pro vás obtížné pochopit, pokračujte, pokračujte ve čtení a vraťte se k němu o něco později.
můžeme přepsat nejen metody, ale také pole třídy.
i když je složité chování, když máme přístup k potlačené pole v mateřské konstruktoru, zcela odlišné od většiny ostatních programovacích jazyků.,
Vezměme si tento příklad:
třída Rabbit
rozšiřuje Animal
přepíše name
pole s jeho vlastní hodnotu.
neexistuje žádný vlastní konstruktor v Rabbit
, takže Animal
Konstruktor se nazývá.
Co je zajímavé je, že v obou případech: new Animal()
new Rabbit()
alert
na řádek (*)
animal
.,
jinými slovy, Nadřazený Konstruktor vždy používá svou vlastní hodnotu pole, nikoli přepsanou hodnotu.
Co je na tom divného?
pokud to ještě není jasné, porovnejte prosím s metodami.
zde je stejný kód, ale místothis.name
pole voláme this.showName()
metoda:
poznámka: nyní je výstup jiný.
a to přirozeně očekáváme. Když je nadřazený Konstruktor volán v odvozené třídě, používá metodu přepsání.
…ale u třídních polí tomu tak není. Jak již bylo řečeno, Nadřazený Konstruktor vždy používá mateřské pole.,
proč je rozdíl?
důvod je v pořadí inicializace pole. Třída pole je inicializován:
- Před konstruktor základní třídy (to se nevztahuje na nic),
- Okamžitě po
super()
pro odvozené třídy.
v našem případě je odvozená třídaRabbit
. Není v něm constructor()
. Jak již bylo řečeno, je to stejné, jako kdyby byl prázdný Konstruktor pouze s super(...args)
.,
, new Rabbit()
hovory super()
, tak vykonávajícím rodič konstruktor, a (za pravidlo pro odvozené třídy), až po to, že jeho třída pole jsou inicializovány. V době provedení nadřazeného konstruktoru neexistují žádná pole třídy Rabbit
, proto se používají pole Animal
.
Tento jemný rozdíl mezi pole a metody specifické pro JavaScript
Naštěstí, toto chování pouze tehdy, projevuje-li přepsat pole se používá v mateřské konstruktoru., Pak může být těžké pochopit, co se děje, takže to vysvětlujeme zde.
Pokud se stane problémem, lze jej opravit pomocí metod nebo getters / setters namísto polí.
Super: internals,]
Pokud čtete tutoriál poprvé-tato část může být přeskočena.
jedná se o vnitřní mechanismy dědičnosti a super
.
pojďme se trochu hlouběji pod kapotou super
. Cestou uvidíme několik zajímavých věcí.,
nejprve říci, ze všeho, co jsme se dosud naučili, je nemožné, aby super
pracovat vůbec!
ano, opravdu si položme otázku, jak by to mělo technicky fungovat? Když metoda objektu běží, dostane aktuální objekt jako this
. Pokud zavoláme super.method()
, musí motor získat method
z prototypu aktuálního objektu. Ale jak?
úkol se může zdát jednoduchý, ale není., Motor zná aktuální objekt this
, tak by to mohlo být nadřazený method
this.__proto__.method
. Bohužel takové „naivní“ řešení nebude fungovat.
pojďme demonstrovat problém. Bez tříd, použití prostých objektů kvůli jednoduchosti.
tuto část můžete přeskočit a přejít níže do podsekce ]
, pokud nechcete znát podrobnosti. To neublíží. Nebo si přečtěte, pokud máte zájem o pochopení věcí do hloubky.
v níže uvedeném příkladu rabbit.__proto__ = animal
., Nyní pojďme vyzkoušet: v rabbit.eat()
budeme říkat animal.eat()
pomocí this.__proto__
:
Na řádek (*)
eat
od prototypu (animal
) a volání v rámci stávajícího objektu. Vezměte prosím na vědomí, že .call(this)
je zde důležité, protože jednoduchý this.__proto__.eat()
by se provést rodič eat
v souvislosti prototyp, není aktuální objekt.,
a ve výše uvedeném kódu skutečně funguje tak, jak bylo zamýšleno: máme správné alert
.
nyní přidáme do řetězce ještě jeden objekt. Uvidíme, jak se věci zlomí:
kód již nefunguje! Vidíme chybu při pokusu o volání longEar.eat()
.
nemusí to být tak zřejmé, ale pokud vysledujeme longEar.eat()
volání, pak můžeme vidět proč. V obou linky (*)
(**)
hodnota this
je aktuální objekt (longEar
)., To je zásadní: všechny objektové metody získají aktuální objekt jako this
, nikoli prototyp nebo tak něco.
Tady je obrázek toho, co se stane:
problém může být vyřešen pomocí this
sám.
]
pro poskytnutí řešení JavaScript přidá ještě jednu speciální interní vlastnost pro funkce: ]
.,
když je funkce zadána jako metoda třídy nebo objektu, stane se tímto objektem její vlastnost ]
.
pak super
používá k vyřešení nadřazeného prototypu a jeho metod.
Pojďme se podívat, jak to funguje, první s čistou objekty:
Metody nejsou „volné“
Jak jsme znali dříve, obecně funkce jsou „zdarma“, není vázán na objekty v Javascriptu. Takže mohou být zkopírovány mezi objekty a volány s jiným this
.,
samotná existence ]
tento princip porušuje, protože metody si pamatují své objekty. ]
nelze změnit, takže tato vazba je navždy.
jediné místo v jazyce, kde se používá ]
– je super
. Pokud tedy metoda nepoužívá super
, můžeme ji stále považovat za bezplatnou a kopírovat mezi objekty. Ale s super
se věci mohou pokazit.,
Tady je demo špatně super
výsledek po zkopírování:
volání tree.sayHi()
ukazuje „jsem zvíře“. Rozhodně špatně.
důvod je jednoduchý:
Zde je schéma toho, co se stane:
Metody, funkce, vlastnosti
rozdíl může být non-podstatné pro nás, ale je to důležité pro JavaScript.
v níže uvedeném příkladu se pro srovnání používá syntaxe bez metody., ]
vlastnost není nastavena a dědictví nebude fungovat:
Shrnutí
- prodloužit třídu:
class Child extends Parent
:- To znamená,
Child.prototype.__proto__
Parent.prototype
, tak metody se dědí.
- To znamená,
- Když se přepisuje konstruktor:
- Musíme volání parent konstruktoru jako
super()
Child
konstruktoru, než pomocíthis
.,
- Musíme volání parent konstruktoru jako
- Při přepsání jinou metodu:
- můžeme použít
super.method()
Child
metoda:Parent
metoda.
- můžeme použít
- Interní:
- Metody vzpomenout si na své třídě/objektu ve vnitřní
]
majetku. Taktosuper
řeší rodičovské metody. - takže není bezpečné kopírovat metodu s
super
z jednoho objektu do druhého.,
- Metody vzpomenout si na své třídě/objektu ve vnitřní
I:
- Šipky funkce nemají svůj vlastní
this
nebosuper
, tak se transparentně zapadají do kontextu.
Napsat komentář