Ist es möglich, eine Klasse in ES6 zu erweitern, ohne die super
-Methode aufzurufen, um die übergeordnete Klasse aufzurufen?
EDIT: Die Frage könnte irreführend sein. Ist es der Standard, den wir super()
nennen müssen, oder fehlt mir etwas?
Zum Beispiel:
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();
Wenn ich nicht super()
für die abgeleitete Klasse anrufe, erhalte ich ein Bereichsproblem -> this is not defined
Ich führe dies mit iojs --harmony in v2.3.0 aus
Die Regeln für ES2015 (ES6) -Klassen ergeben sich im Wesentlichen aus:
this
erst verwendet werden, wenn super
aufgerufen wird.super
aufrufen, wenn es sich um Unterklassen handelt, oder sie müssen ein Objekt explizit zurückgeben, um die Stelle des nicht initialisierten zu ersetzen.Dies betrifft zwei wichtige Abschnitte der ES2015-Spezifikation.
Abschnitt 8.1.1.3.4 definiert die Logik, um zu entscheiden, was this
in der Funktion ist. Für Klassen ist es wichtig, dass es möglich ist, dass this
in einem "uninitialized"
-Status ist. Wenn Sie in diesem Status versuchen, this
zu verwenden, wird eine Ausnahme ausgelöst.
Abschnitt 9.2.2 , [[Construct]]
, der das Verhalten von Funktionen definiert, die über new
oder super
aufgerufen werden. Beim Aufruf eines Basisklassenkonstruktors wird this
in Schritt # 8 von [[Construct]]
initialisiert. In allen anderen Fällen ist this
jedoch nicht initialisiert. Am Ende der Konstruktion wird GetThisBinding
aufgerufen. Wenn super
noch nicht aufgerufen wurde (wodurch this
initialisiert wird) oder ein explizites Ersetzungsobjekt nicht zurückgegeben wurde, wird in der letzten Zeile des Konstruktoraufrufs eine Ausnahme ausgelöst.
Es gab mehrere Antworten und Kommentare, die besagten, dass super
[~ # ~] [~ # ~] muss = Sei die erste Zeile in constructor
. Das ist einfach falsch @loganfsmyth Antwort hat die erforderlichen Referenzen der Anforderungen, aber es läuft auf Folgendes hinaus:
Erben des (extends
) -Konstruktors muss Rufen Sie super
auf, bevor Sie this
verwenden und bevor Sie zurückgeben, auch wenn this
wird nicht verwendet
Siehe Fragment unten (funktioniert in Chrome ...), um herauszufinden, warum es möglicherweise sinnvoll ist, Anweisungen (ohne Verwendung von this
) zu haben, bevor super
aufgerufen wird.
'use strict';
var id = 1;
function idgen() {
return 'ID:' + id++;
}
class Base {
constructor(id) {
this.id = id;
}
toString() { return JSON.stringify(this); }
}
class Derived1 extends Base {
constructor() {
var anID = idgen() + ':Derived1';
super(anID);
this.derivedProp = this.baseProp * 2;
}
}
alert(new Derived1());
Die neue es6-Klassensyntax ist nur eine andere Notation für "alte" es5-Klassen "mit Prototypen. Daher können Sie eine bestimmte Klasse nicht instanziieren, ohne ihren Prototyp (die Basisklasse) festzulegen.
Das ist, als würde man Käse auf sein Sandwich legen, ohne es zu machen. Sie können auch nicht Käse vorher das Sandwich machen, also ...
Das Verwenden des this
-Schlüsselworts vor dem Aufruf der Superklasse mit super()
ist ebenfalls nicht zulässig.
// valid: Add cheese after making the sandwich
class CheeseSandwich extend Sandwich {
constructor() {
super();
this.supplement = "Cheese";
}
}
// invalid: Add cheese before making sandwich
class CheeseSandwich extend Sandwich {
constructor() {
this.supplement = "Cheese";
super();
}
}
// invalid: Add cheese without making sandwich
class CheeseSandwich extend Sandwich {
constructor() {
this.supplement = "Cheese";
}
}
Wenn Sie keinen Konstruktor für eine Basisklasse angeben, wird die folgende Definition verwendet:
constructor() {}
Für abgeleitete Klassen wird der folgende Standardkonstruktor verwendet:
constructor(...args) {
super(...args);
}
BEARBEITEN: Gefunden auf developer.mozilla.org
:
When used in a constructor, the super keyword appears alone and must be used before the this keyword can be used.
Sie müssen sich nur für diese Lösung registrieren, da die Antworten mich hier nicht am wenigsten zufriedenstellen, da es sich eigentlich um einen einfachen Weg handelt. Passen Sie Ihr Klassenerstellungsmuster an, um Ihre Logik in einer Untermethode zu überschreiben, während Sie nur den Superkonstruktor verwenden und leiten Sie die Konstruktorargumente an ihn weiter.
Wie in Ihnen erstellen Sie in Ihren Unterklassen keinen Konstruktor per se, sondern beziehen sich nur auf eine Methode, die in der jeweiligen Unterklasse überschrieben wird.
Das bedeutet, dass du dich von der Konstruktorfunktionalität befreit hast, die auf dich erzwungen wird, und eine reguläre Methode unterlassen - die überschrieben werden kann und nicht zwingt (), wenn du dir die Wahl lässt, ob, wo und wie du möchtest Super anrufen (voll optional) zB:
super.ObjectConstructor(...)
class Observable {
constructor() {
return this.ObjectConstructor(arguments);
}
ObjectConstructor(defaultValue, options) {
this.obj = { type: "Observable" };
console.log("Observable ObjectConstructor called with arguments: ", arguments);
console.log("obj is:", this.obj);
return this.obj;
}
}
class ArrayObservable extends Observable {
ObjectConstructor(defaultValue, options, someMoreOptions) {
this.obj = { type: "ArrayObservable" };
console.log("ArrayObservable ObjectConstructor called with arguments: ", arguments);
console.log("obj is:", this.obj);
return this.obj;
}
}
class DomainObservable extends ArrayObservable {
ObjectConstructor(defaultValue, domainName, options, dependent1, dependent2) {
this.obj = super.ObjectConstructor(defaultValue, options);
console.log("DomainObservable ObjectConstructor called with arguments: ", arguments);
console.log("obj is:", this.obj);
return this.obj;
}
}
var myBasicObservable = new Observable("Basic Value", "Basic Options");
var myArrayObservable = new ArrayObservable("Array Value", "Array Options", "Some More Array Options");
var myDomainObservable = new DomainObservable("Domain Value", "Domain Name", "Domain Options", "Dependency A", "Depenency B");
prost!
Sie können super () in Ihrer Unterklasse weglassen, wenn Sie den Konstruktor in Ihrer Unterklasse vollständig weglassen. Ein verborgener Standardkonstruktor wird automatisch in Ihre Unterklasse aufgenommen. Wenn Sie jedoch den Konstruktor in Ihre Unterklasse aufnehmen, muss super () in diesem Konstruktor aufgerufen werden.
class A{
constructor(){
this.name = 'hello';
}
}
class B extends A{
constructor(){
// console.log(this.name); // ReferenceError
super();
console.log(this.name);
}
}
class C extends B{} // see? no super(). no constructor()
var x = new B; // hello
var y = new C; // hello
Lesen Sie dies für weitere Informationen.
Ich würde empfehlen, OODK-JS zu verwenden, wenn Sie folgende OOP Konzepte entwickeln möchten.
OODK(function($, _){
var Character = $.class(function ($, µ, _){
$.public(function __initialize(){
$.log('invoke character');
});
});
var Hero = $.extends(Character).class(function ($, µ, _){
$.public(function __initialize(){
$.super.__initialize();
$.log('invoke hero');
});
});
var hero = $.new(Hero);
});
Versuchen:
class Character {
constructor(){
if(Object.getPrototypeOf(this) === Character.prototype){
console.log('invoke character');
}
}
}
class Hero extends Character{
constructor(){
super(); // throws exception when not called
console.log('invoke hero');
}
}
var hero = new Hero();
console.log('now let\'s invoke Character');
var char = new Character();
Die Antwort von justyourimage ist der einfachste Weg, aber sein Beispiel ist ein wenig aufgebläht. Hier ist die generische Version:
class Base {
constructor(){
return this._constructor(...arguments);
}
_constructor(){
// just use this as the constructor, no super() restrictions
}
}
class Ext extends Base {
_constructor(){ // _constructor is automatically called, like the real constructor
this.is = "easy"; // no need to call super();
}
}
Erweitern Sie nicht die eigentliche constructor()
, sondern verwenden Sie einfach die gefälschte _constructor()
für die Instantiierungslogik.
Beachten Sie, dass diese Lösung das Debuggen lästig macht, da Sie für jede Instantiierung eine zusätzliche Methode verwenden müssen.
Einfache Lösung: Ich denke, es ist keine Erklärung erforderlich.
class ParentClass() {
constructor(skipConstructor = false) { // default value is false
if(skipConstructor) return;
// code here only gets executed when 'super()' is called with false
}
}
class SubClass extends ParentClass {
constructor() {
super(true) // true for skipping ParentClass's constructor.
// code
}
}