Czy można rozszerzyć klasę w ES6 bez wywoływania super
metody wywołującej klasę nadrzędną?
EDYCJA: Pytanie może być mylące. Czy to standard, do którego musimy zadzwonić, super()
czy czegoś mi brakuje?
Na przykład:
class Character {
constructor(){
console.log('invoke character');
}
}
class Hero extends Character{
constructor(){
super(); // exception thrown here when not called
console.log('invoke hero');
}
}
var hero = new Hero();
Kiedy nie wywołuję super()
klasy pochodnej, pojawia się problem z zakresem ->this is not defined
Używam tego z iojs --harmony w wersji 2.3.0
javascript
class
inheritance
ecmascript-6
xhallix
źródło
źródło
Odpowiedzi:
Zasady dla klas ES2015 (ES6) sprowadzają się zasadniczo do:
this
nie można jej używać, dopóki niesuper
zostanie wywołana.super
jeśli są podklasami, lub muszą jawnie zwrócić jakiś obiekt, aby zastąpić ten, który nie został zainicjowany.Sprowadza się to do dwóch ważnych sekcji specyfikacji ES2015.
Sekcja 8.1.1.3.4 definiuje logikę decydującą o zawartości
this
funkcji. Ważną częścią klas jest to, że możnathis
być w"uninitialized"
stanie, a gdy jest w tym stanie, próba użyciathis
spowoduje zgłoszenie wyjątku.Sekcja 9.2.2 ,
[[Construct]]
w której zdefiniowano zachowanie funkcji wywoływanych przeznew
lubsuper
. Podczas wywoływania konstruktora klasy bazowejthis
jest inicjowany w kroku # 8 programu[[Construct]]
, ale we wszystkich innych przypadkachthis
jest niezainicjalizowany. Na końcu konstrukcjiGetThisBinding
jest wywoływana, więc jeślisuper
nie została jeszcze wywołana (a tym samym inicjalizacjathis
) lub nie został zwrócony jawny obiekt zastępczy, ostatnia linia wywołania konstruktora zgłosi wyjątek.źródło
super()
?super()
konstruktora?return Object.create(new.target.prototype, …)
aby uniknąć wywoływania super konstruktora.Było wiele odpowiedzi i komentarzy stwierdzających, że
super
MUSI to być pierwszy wiersz w środkuconstructor
. To jest po prostu złe. @loganfsmyth answer zawiera wymagane odniesienia do wymagań, ale sprowadza się to do:extends
Konstruktor Inheriting ( ) musi wywołaćsuper
przed użyciemthis
i przed zwróceniem, nawet jeślithis
nie jest używanyZobacz fragment poniżej (działa w Chrome ...), aby zobaczyć, dlaczego może mieć sens posiadanie instrukcji (bez użycia
this
) przed wywołaniemsuper
.źródło
"See fragment below (works in Chrome...)"
otwórz konsolę chrom wywoływacza i kliknij „Run fragmencie kodu”:Uncaught ReferenceError: this is not defined
. Jasne, możesz używać metod w konstruktorze wcześniej,super()
ale nie możesz używać metod z klasy wcześniej!this
wcześniejsuper()
(Twój kod to udowodni) nie ma nic wspólnego ze specyfikacją natychmiastową, ale z implementacją javascript. Więc przed słowem „to” musisz nazwać „super”.super
, a ty stwierdzałeś, że używanie tego jest nielegalnethis
przed zadzwonieniemsuper
. Oboje mamy rację, po prostu się nie rozumieliśmy :-) (I ten wyjątek był zamierzony, aby pokazać, co nie jest legalne - nawet nazwałem nieruchomość „WillFail”)Nowa składnia klasy es6 jest tylko inną notacją dla "starych" klas "es5" z prototypami. Dlatego nie można utworzyć wystąpienia określonej klasy bez ustawienia jej prototypu (klasy bazowej).
To jak umieszczanie sera na kanapce bez jej przyrządzania. Nie możesz też ułożyć sera przed zrobieniem kanapki, więc ...
... użycie
this
słowa kluczowego przed wywołaniem superklasy with teżsuper()
jest niedozwolone.Jeśli nie określisz konstruktora dla klasy bazowej, używana jest następująca definicja:
W przypadku klas pochodnych używany jest następujący konstruktor domyślny:
EDYCJA: Znaleziono to w
developer.mozilla.org
:Źródło
źródło
this
w ogóle nie jest używany. 2. JS nie jest kanapką, aw ES5 zawsze możesz użyćthis
, nawet przed wywołaniem jakiejkolwiek innej funkcji, którą lubisz (która może lub nie definiuje właściwości dodatku)this
?! 2. Moja klasa JS reprezentuje kanapkę, aw ES6 nie zawsze możesz jej użyćthis
. Próbuję tylko wyjaśnić klasy es6 (metaforą) i nikt nie potrzebuje takich destrukcyjnych / niepotrzebnych komentarzy.Właśnie zarejestrowałem się, aby opublikować to rozwiązanie, ponieważ odpowiedzi tutaj nie satysfakcjonują mnie najmniej, ponieważ w rzeczywistości istnieje prosty sposób obejścia tego. Dostosuj wzorzec tworzenia klas, aby nadpisać logikę w metodzie podrzędnej, używając tylko konstruktora super, i przekaż argumenty konstruktorów do niego.
Tak jak w przypadku, nie tworzysz konstruktora w swoich podklasach jako takich, a jedynie odniesienie do metody, która jest nadpisana w odpowiedniej podklasie.
Oznacza to, że uwalniasz się od funkcji konstruktora narzuconej tobie i powstrzymujesz się od zwykłej metody - która może być nadpisana i nie wymusza super (), gdy pozwalasz sobie na wybór, czy, gdzie i jak chcesz wywołać super (w pełni opcjonalnie) np:
Twoje zdrowie!
źródło
Możesz pominąć super () w swojej podklasie, jeśli całkowicie pominiesz konstruktora w swojej podklasie. „Ukryty” domyślny konstruktor zostanie automatycznie dołączony do Twojej podklasy. Jeśli jednak włączysz konstruktor do swojej podklasy, w tym konstruktorze musi zostać wywołana funkcja super ().
Przeczytaj to, aby uzyskać więcej informacji.
źródło
Odpowiedź justyourimage jest najłatwiejsza, ale jego przykład jest trochę nadęty. Oto wersja ogólna:
Nie rozszerzaj rzeczywistości
constructor()
, po prostu użyj fałszywej_constructor()
logiki tworzenia instancji.Zwróć uwagę, że to rozwiązanie sprawia, że debugowanie jest denerwujące, ponieważ musisz przejść do dodatkowej metody dla każdej instancji.
źródło
Próbować:
Demo
źródło
A constructor *can* use the super keyword to call the constructor of a parent class.
więc powiedziałbym, że poczekaj na wydanie ES6Polecam użycie OODK-JS, jeśli zamierzasz rozwijać następujące koncepcje OOP.
źródło
Proste rozwiązanie: myślę, że nie ma potrzeby wyjaśniania.
źródło
@Bergi wspomniałem
new.target.prototype
, ale szukałem konkretnego przykładu udowadniającego, że możesz uzyskać dostępthis
(lub lepiej, odwołanie do obiektu, za pomocą którego tworzy kod klientanew
, patrz poniżej) bez konieczności wywoływaniasuper()
.Rozmowa jest tania, pokaż mi kod ... Oto przykład:
Który wyświetli:
Więc widać, że są skutecznie tworząc obiekt typu
B
(klasy dziecko), która jest również obiektem typuA
(swojej klasie dominującej) oraz w ramachchildMethod()
dzieckaB
mamythis
skierowaną do obiektuobj
, który stworzyliśmy w Bconstructor
zObject.create(new.target.prototype)
.A wszystko to bez żadnej troski
super
.Wykorzystuje to fakt, że w JS a
constructor
może zwrócić zupełnie inny obiekt, gdy kod klienta konstruuje nową instancję znew
.Mam nadzieję, że to komuś pomoże.
źródło