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.,

Každý výraz je povoleno po 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 Rabbitnemě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ím this.

… 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 do this.
  • 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

Pokročilá 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,]

pokročilé informace

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í

  1. prodloužit třídu: class Child extends Parent:
    • To znamená, Child.prototype.__proto__ Parent.prototype, tak metody se dědí.
  2. Když se přepisuje konstruktor:
    • Musíme volání parent konstruktoru jako super() Child konstruktoru, než pomocí this.,
  3. Při přepsání jinou metodu:
    • můžeme použít super.method() Child metoda: Parent metoda.
  4. Interní:
    • Metody vzpomenout si na své třídě/objektu ve vnitřní ] majetku. Takto super řeší rodičovské metody.
    • takže není bezpečné kopírovat metodu s super z jednoho objektu do druhého.,

I:

  • Šipky funkce nemají svůj vlastní this nebo super, tak se transparentně zapadají do kontextu.