Sechs Vererbungsmethoden in JS und ihre Vor- und Nachteile

Sechs Vererbungsmethoden in JS und ihre Vor- und Nachteile

Vorwort

Vererbung ist ein unverzichtbarer Bestandteil der JS-Welt und wird als einer der drei Berge von JS bezeichnet. Mit dieser Methode können wir den vorherigen Entwicklungscode besser wiederverwenden, den Entwicklungszyklus verkürzen und die Entwicklungseffizienz verbessern.

Vor ES6 wurden Klassen in JS durch Konstruktoren simuliert und es gab keine echten Klassen. Obwohl die Klasse in ES6 ein Syntaxzucker ist, konnten Klassen in dieser Zeit direkt als Funktionen verwendet werden. Nach ES6 können Klassen nicht mehr als Funktionen verwendet werden.

Bevor wir über Vererbung sprechen, müssen wir zunächst klarstellen, dass es in einer Klasse zwei Arten von Attributen gibt: Instanzattribute und öffentliche Attribute. Alle im Folgenden besprochenen Vererbungsmethoden drehen sich um diese beiden Punkte.

Funktion Tier(Name) {
  // Attribut der Instanz this.name = name;
}

// Öffentliche Eigenschaften Animal.prototype.eat = function() {
  // zu erledigen ...
}

Wie vermeidet man, Konstruktoren vor ES6 direkt als Funktionen aufzurufen?

ES5-Lösung:

Funktion Tier() {
    // Bei direktem Aufruf ohne Verwendung von new wird eine Ausnahme ausgelöst, wenn (!(diese Instanz von Animal)) {
        // Das Prinzip von new. Wenn new verwendet wird, handelt es sich um eine Instanz von Animal, dann ist diese Instanz von Animal wahr
        throw new Error("Den Konstruktor nicht direkt aufrufen");
    }
}

ES6 und spätere Lösungen:

Funktion Tier() {
    // Wenn new verwendet wird, zeigt new.target auf sich selbst, andernfalls ist es undefiniert. Es kann jedoch nicht beim Erben verwendet werden, da das ursprüngliche es5 beim Erben von Eigenschaften einer Instanz Animal.call(this) if (!new.target) { verwendet.
        throw new Error("Den Konstruktor nicht direkt aufrufen");
    }
}

Beide der oben genannten Lösungen können gelöst werden, indem sie direkt als Funktionen aufgerufen werden. Wenn Sie die Konsole direkt aufrufen, wird ein Fehler gemeldet: Nicht abgefangener Fehler: Rufen Sie den Konstruktor nicht direkt auf

Als nächstes werfen wir einen Blick auf die Vererbungsmethoden in JS

Vererbung von Prototypketten

Die Vererbung in der Prototypkette ist eine der gebräuchlichsten Vererbungsmethoden. Zwischen dem beteiligten Konstruktor, Prototyp und der Instanz besteht eine bestimmte Beziehung, d. h. jeder Konstruktor hat ein Prototypobjekt, das Prototypobjekt enthält einen Zeiger auf den Konstruktor und die Instanz enthält einen Zeiger auf das Prototypobjekt.

Funktion Person(Name) {
    dieser.name = Name;
    this.permission = ["Benutzer", "Gehalt", "Urlaub"];
}

Person.prototype.say = Funktion () {
    console.log(`${this.name} hat gesprochen`);
};

Funktion Personal(Alter) {
    dieses.Alter = Alter;
}

Mitarbeiter.Prototyp = neue Person("Zhang San");

const zs = neues Personal(12);
console.log(zs.name); // Zhang Sanzs.say(); // Zhang San hat gesprochen

An diesem Punkt entspricht der Code den Erwartungen. Erstellen Sie als Nächstes eine Instanz und ändern Sie den Namen und die Berechtigung.

const zs = neues Personal(12);
const zs2 = neues Personal(18);
zs.permission.pop()
zs.name = "Li Si";

Konsole.log(zs.name);
console.log(zs2.name);
console.log(zs.permission);
console.log(zs2.permission);

Die Ausgaben der ersten beiden sind: Li Si und Zhang San, während die Ausgaben der letzten beiden gleich sind, beide ["Benutzer", "Gehalt"]. Warum passiert das?
Wenn zs.name = '李四'; ausgeführt wird, handelt es sich tatsächlich um eine Zuweisungsoperation. Nach der Zuweisung wird zs

zs2.name durchsucht weiterhin die Prototypenkette, sodass die ersten beiden Ausgaben Li Si und Zhang San sind

Durch die Ausgabe von true über console.log(zs.__proto__ === zs2.__proto__); können wir erkennen, dass die beiden Instanzen dasselbe Prototypobjekt Person verwenden und ihren Speicherplatz gemeinsam nutzen. Wenn sich eine ändert, ändert sich auch die andere entsprechend.

Aus dem oben Gesagten geht hervor, dass die Vererbung von Prototypketten einige Nachteile hat

Konstruktorvererbung

Konstruktoren verwenden normalerweise call und apply, um die Vererbung abzuschließen

Funktion Person(Name) {
    dieser.name = Name;
    this.permission = ["Benutzer", "Gehalt", "Urlaub"];
}

Person.prototype.say = Funktion () {
    console.log(`${this.name} hat gesprochen`);
};

Funktion Mitarbeiter(Name, Alter) {
    Person.call(dieser, Name);
    dieses.Alter = Alter;
}

Mitarbeiter.prototype.eat = Funktion () {
    console.log('Lass uns essen~~~~');
}

const zs = new Staff("Zahl", 12);
konsole.log(zs);

Der obige Code gibt die Konsole aus:

Es ist ersichtlich, dass es nicht nur die Eigenschaften und Methoden von Staff hat, sondern auch die Eigenschaften von Person erbt, da Person.call (this, name) bei jeder Instanziierung aufgerufen wird, wodurch das Problem der Vererbung der Prototypkette gelöst werden kann.

Rufen Sie zu diesem Zeitpunkt die Methode für den Personenprototyp auf

zs.sagen()

Zu diesem Zeitpunkt meldet die Konsole einen Fehler: Uncaught TypeError: zs.say ist keine Funktion

Kombinationsvererbung (Kombination aus Prototypkettenvererbung und Konstruktorvererbung)

Sowohl die Prototypkettenvererbung als auch die Konstruktorvererbung haben ihre eigenen Probleme und Vorteile. Durch die Kombination der beiden Vererbungsmethoden entsteht eine zusammengesetzte Vererbung.

Funktion Person(Name) {
    dieser.name = Name;
    this.permission = ["Benutzer", "Gehalt", "Urlaub"];
}

Person.prototype.say = Funktion () {
	console.log(`${this.name} hat gesprochen`);
};

Funktion Mitarbeiter(Name, Alter) {
    // Zweite Ausführung von Person
    Person.call(dieser, Name);
    dieses.Alter = Alter;
}

Mitarbeiter.prototype.eat = Funktion () {
    console.log("Lass uns essen~~~~");
};

// Erste Ausführung von Person
Mitarbeiter.Prototyp = neue Person();
// Wenn Sie den Staff-Konstruktor nicht zurück auf Staff verweisen, verweist die Staff-Instanz zs.constructor auf Person
Staff.prototype.constructor = Mitarbeiter;

const zs = new Staff("Zahl", 12);
const ls = neuer Stab("Li Si", 12);
zs.permission.pop();
console.log(zs.permission);
console.log(ls.permission);
zs.sagen();
ls.sagen();

Vorerst ist die Konsolenausgabe normal und die beiden oben genannten Vererbungsmängel sind behoben, es treten jedoch zwei neue Probleme auf:

  1. Person wird zweimal ausgeführt: Person.call(this, name) und new Person(). Es wird erwartet, dass es einmal ausgeführt wird. Die zusätzliche Ausführung verursacht Leistungseinbußen.
  2. Wenn Staff.prototype = new Person() einige öffentliche Eigenschaften und Methoden definiert, werden diese überschrieben. Sie können beispielsweise zs.eat() nicht für eine Instanz aufrufen, und die Konsole meldet den Fehler Uncaught TypeError: zs.eat ist keine Funktion. Wenn Sie es danach definieren, wird es Person verunreinigen.

Parasitäre Vererbung

Indem Object.create verwendet wird, um eine oberflächliche Kopie des Zielobjekts zu erhalten, und dann einige Methoden hinzugefügt werden, um eine Verschmutzung der Basisklasse zu vermeiden, wird hauptsächlich das zweite Problem der zusammengesetzten Vererbung gelöst.

Ersetzen Sie hauptsächlich die folgenden beiden Codezeilen

Mitarbeiter.Prototyp = neue Person();
Staff.prototype.constructor = Mitarbeiter;

Ersetzen durch:

Mitarbeiter.Prototyp = Objekt.Erstellen(Person.Prototyp, {
    Konstruktor: {
        // Wenn Sie den Staff-Konstruktor nicht zurück auf Staff verweisen, verweist die Staff-Instanz zs.constructor auf Person
        Wert: Mitarbeiter,
    },
});

Kombinatorische parasitäre Vererbung

Bisher besteht noch das Problem der zweimaligen Instanziierung von Personen, das nicht gelöst wurde. Die folgende kombinierte parasitäre Vererbung kann das obige Problem perfekt lösen. Dies ist auch die beste Vererbungsmethode unter allen Vererbungsmethoden vor ES6.

Der vollständige Code lautet wie folgt:

Funktion Person(Name) {
    dieser.name = Name;
    this.permission = ["Benutzer", "Gehalt", "Urlaub"];
}

Person.prototype.say = Funktion () {
    console.log(`${this.name} hat gesprochen`);
};

Funktion Mitarbeiter(Name, Alter) {
    Person.call(dieser, Name);
    dieses.Alter = Alter;
}

Mitarbeiter.Prototyp = Objekt.Erstellen(Person.Prototyp, {
    Konstruktor: {
        // Wenn Sie den Staff-Konstruktor nicht zurück auf Staff verweisen, verweist die Staff-Instanz zs.constructor auf Person
        Wert: Mitarbeiter,
    },
});

Mitarbeiter.prototype.eat = Funktion () {
    console.log("Lass uns essen~~~~");
};

Tatsächlich gibt es beim Erben mehr Möglichkeiten, Staff.prototype zu ändern, auf das verwiesen wird, als nur die oben genannten. Es gibt auch einige andere Methoden

  • prototype.__proto__-Methode
Mitarbeiter.prototype.__proto__ = Person.prototype

Es gibt ein Kompatibilitätsproblem mit prototype.__proto__. Es kann nicht von selbst gefunden werden. Es sucht weiter nach oben durch die Prototypenkette. Zu diesem Zeitpunkt teilen sich Animal und Tiger nicht mehr dieselbe Adresse und beeinflussen sich nicht gegenseitig.

  • Object.setPrototypeOf-Methode
Objekt.setPrototypeOf(Mitarbeiter.Prototyp, Person.Prototyp)

es6-Syntax, es besteht Kompatibilität, das Prinzip ist die Methode prototype.__proto__

erweitert

Nach ES6 können Sie Extends zur Vererbung verwenden, was auch die am häufigsten verwendete Methode in der aktuellen Entwicklung ist. Obwohl die Browserunterstützung nicht ideal ist, sind dies mit der Verbesserung der heutigen Technik keine Gründe mehr, die Verwendung einzuschränken.

Klasse Person {
    Konstruktor(Name) {
        dieser.name = Name;
        this.permission = ["Benutzer", "Gehalt", "Urlaub"];
    }

    sagen() {
        console.log(`${this.name} hat gesprochen`);
    }
}

Klasse Staff erweitert Person {
    Konstruktor(Name, Alter) {
        super(name);
        dieses.Alter = Alter;
    }

    essen() {
        console.log("Lass uns essen~~~~");
    }
}

Tatsächlich wird nach der Kompilierung der ES6-Vererbung durch Babel auch die kombinierte parasitäre Vererbung übernommen, sodass wir uns auf die Beherrschung des Vererbungsprinzips konzentrieren müssen.

Zusammenfassen

Damit ist dieser Artikel über die sechs Vererbungsmethoden und ihre Vor- und Nachteile in JS abgeschlossen. Weitere Informationen zu JS-Vererbungsmethoden und ihren Vor- und Nachteilen finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • JavaScript-Vererbung in einem Artikel verstehen
  • Zusammenfassung von 6 gängigen Vererbungsmethoden in js
  • 6 Vererbungsmethoden von JS Advanced ES6
  • Detaillierte Erläuterung nativer Javascript-Vererbungsmethoden und ihrer Vor- und Nachteile
  • Detaillierte Erläuterung der 6 Möglichkeiten der JS-Vererbung
  • Mehrere Möglichkeiten zur Implementierung der Vererbung in JavaScript
  • 6 JavaScript-Vererbungsmethoden und ihre Vor- und Nachteile (Zusammenfassung)
  • Beispiele für mehrere gängige Möglichkeiten zur Implementierung der Vererbung in JS
  • Mehrere Vererbungsmethoden in JavaScript teilen

<<:  Lösen Sie das Problem der Ausführung von „Hello World“ nach der Docker-Installation

>>:  So stellen Sie mit Navicat Premium eine Remoteverbindung zur MySQL-Datenbank her

Artikel empfehlen

Mysql NULL verursachte die Grube

Verwenden von NULL in Vergleichsoperatoren mysql&...

Analyse des MySQL-Warnprotokolls zu abgebrochenen Verbindungen

Vorwort: Manchmal wird die mit MySQL verbundene S...

Docker-Container: benutzerdefinierter Host-Netzwerkzugriffsvorgang

Durch Hinzufügen des Schlüsselworts extra_hosts i...

Lösung für die Auswirkungen leerer Pfade auf die Seitenleistung

Vor ein paar Tagen habe ich einen von Yu Bo getei...

SMS-Bestätigungscode-Anmeldefunktion basierend auf Antd Pro (Prozessanalyse)

Inhaltsverzeichnis Zusammenfassung Gesamtprozess ...

Rückgängigmachen der Anmeldung in MySQL

Konzepteinführung: Wir wissen, dass das Redo-Log ...

Implementierung der Kommunikation zwischen Vue und Flask

axios installieren und Kommunikation implementier...

So ändern Sie $ in # in Linux

In diesem System steht das #-Zeichen für den Root...

Einige Vorschläge zur Verbesserung der Nginx-Leistung

Wenn Ihre Webanwendung nur auf einer Maschine läu...

Vue+Openlayer verwendet modify, um den gesamten Code des Elements zu ändern

Vue+Openlayer verwendet „modify“, um Elemente zu ...

So ändern Sie die Farbe der gesamten Zeile (tr), wenn die Maus in HTML stoppt

Verwenden Sie reines CSS, um die Hintergrundfarbe...