Einführung
JavaScript ist eine prototypbasierte Sprache, und jedes Objekt in JavaScript verfügt über eine versteckte interne Eigenschaft namens ]
, mit der Objekteigenschaften und-methoden erweitert werden können. Sie können mehr über Prototypen in unserem Verständnis Prototypen und Vererbung in JavaScript Tutorial lesen.
Bis vor kurzem verwendeten fleißige Entwickler Konstruktorfunktionen, um ein objektorientiertes Entwurfsmuster in JavaScript nachzuahmen., Die Sprachspezifikation ECMAScript 2015, oft als ES6 bezeichnet, führte Klassen in die JavaScript-Sprache ein. Klassen in JavaScript bieten keine zusätzliche Funktionalität und werden oft als „syntaktischer Zucker“ gegenüber Prototypen und Vererbung beschrieben, da sie eine sauberere und elegantere Syntax bieten. Da andere Programmiersprachen Klassen verwenden, macht die Klassensyntax in JavaScript es Entwicklern einfacher, zwischen Sprachen zu wechseln.
Klassen sind Funktionen
Eine JavaScript-Klasse ist ein Funktionstyp., Klassen werden mit dem Schlüsselwort class
deklariert. Wir werden die Funktionsausdruckssyntax verwenden, um eine Funktions-und Klassenausdruckssyntax zu initialisieren, um eine Klasse zu initialisieren.
// Initializing a function with a function expressionconst x = function() {}
// Initializing a class with a class expressionconst y = class {}
Mit der Methode Object.getPrototypeOf()
können wir auf die ]
eines Objekts zugreifen. Verwenden wir das, um die leere Funktion zu testen, die wir erstellt haben.
Object.getPrototypeOf(x);
Outputƒ () { }
Wir können diese Methode auch für die gerade erstellte Klasse verwenden.,
Object.getPrototypeOf(y);
Outputƒ () { }
Der mit function
deklarierte Code und class
geben beide eine Funktion zurück ]
. Bei Prototypen kann jede Funktion mithilfe des Schlüsselworts new
zu einer Konstruktorinstanz werden.
Dies gilt auch für Klassen.
Outputy {}constructor: class
Diese Prototypkonstruktorbeispiele sind ansonsten leer, aber wir können sehen, wie unter der Syntax beide Methoden das gleiche Endergebnis erzielen.,
Klasse definieren
Im Tutorial Prototypen und Vererbung haben wir ein Beispiel erstellt, das auf der Erstellung von Charakteren in einem textbasierten Rollenspiel basiert. Fahren wir mit diesem Beispiel hier fort, um die Syntax von Funktionen auf Klassen zu aktualisieren.
Eine Konstruktorfunktion wird mit einer Reihe von Parametern initialisiert, die als Eigenschaften von this
zugewiesen werden und sich auf die Funktion selbst beziehen. Der erste Buchstabe der Kennung würde durch Konvention großgeschrieben.
// Initializing a constructor functionfunction Hero(name, level) { this.name = name; this.level = level;}
Wenn wir dies in die unten gezeigte Klassensyntax übersetzen, sehen wir, dass es sehr ähnlich strukturiert ist.
// Initializing a class definitionclass Hero { constructor(name, level) { this.name = name; this.level = level; }}
Wir wissen, dass eine Konstruktorfunktion durch die Großschreibung des ersten Buchstabens des Initialisierers (optional) und durch Vertrautheit mit der Syntax ein Objektbauplan sein soll. Das Schlüsselwort class
kommuniziert das Ziel unserer Funktion einfacher.,
Der einzige Unterschied in der Syntax der Initialisierung besteht darin, das Schlüsselwort class
anstelle von function
zu verwenden und die Eigenschaften innerhalb einer constructor()
– Methode zuzuweisen.
Methoden definieren
Bei Konstruktorfunktionen ist es üblich, Methoden direkt der prototype
anstelle der Initialisierung zuzuweisen, wie in der greet()
– Methode unten zu sehen ist.
Mit Klassen wird diese Syntax vereinfacht und die Methode kann direkt zur Klasse hinzugefügt werden., Mit der in ES6 eingeführten Methodendefinitionskürzung ist das Definieren einer Methode ein noch prägnanterer Prozess.
Schauen wir uns diese Eigenschaften und Methoden in Aktion an. Wir erstellen eine neue Instanz von Hero
mit dem Schlüsselwort new
und weisen einige Werte zu.
const hero1 = new Hero('Varg', 1);
Wenn wir mehr Informationen über unser neues Objekt mit console.log(hero1)
ausdrucken, können wir mehr Details darüber sehen, was mit der Klasseninitialisierung passiert.,
OutputHero {name: "Varg", level: 1}__proto__: ▶ constructor: class Hero ▶ greet: ƒ greet()
Wir können in der Ausgabe sehen, dass die Funktionen constructor()
und greet()
auf die __proto__
oder ]
von hero1
, und nicht direkt als Methode für das hero1
– Objekt. Während dies beim Erstellen von Konstruktorfunktionen klar ist, ist es beim Erstellen von Klassen nicht offensichtlich. Klassen ermöglichen eine einfachere und prägnantere Syntax, opfern jedoch einige Klarheit im Prozess.,
Erweitern einer Klasse
Ein vorteilhaftes Merkmal von Konstruktorfunktionen und-klassen besteht darin, dass sie basierend auf dem übergeordneten Objekt in neue Objektbaupläne erweitert werden können. Dies verhindert die Wiederholung von Code für Objekte, die ähnlich sind, aber einige zusätzliche oder spezifischere Funktionen benötigen.
Neue Konstruktorfunktionen können mit der call()
– Methode aus dem übergeordneten Element erstellt werden., Im folgenden Beispiel erstellen wir eine spezifischere Zeichenklasse mit dem Namen Mage
und weisen die Eigenschaften von Hero
mit call()
zu und fügen eine zusätzliche Eigenschaft hinzu.
An dieser Stelle können wir eine neue Instanz von Mage
mit denselben Eigenschaften wie Hero
sowie eine neue Instanz von Mage
.,
const hero2 = new Mage('Lejon', 2, 'Magic Missile');
Wenn wir hero2
an die Konsole senden, können wir sehen, dass wir basierend auf dem Konstruktor eine neue Mage
erstellt haben.
OutputMage {name: "Lejon", level: 2, spell: "Magic Missile"}__proto__: ▶ constructor: ƒ Mage(name, level, spell)
Bei ES6-Klassen wird anstelle von call
das Schlüsselwort super
verwendet, um auf die übergeordneten Funktionen zuzugreifen. Wir verwenden extends
, um auf die übergeordnete Klasse zu verweisen.
Jetzt können wir auf dieselbe Weise eine neue Mage
Instanz erstellen.,
const hero2 = new Mage('Lejon', 2, 'Magic Missile');
Wir drucken hero2
auf die Konsole und zeigen die Ausgabe an.
Die Ausgabe ist fast genau gleich, außer dass in der Klassenkonstruktion die ]
mit dem übergeordneten Element verknüpft ist, in diesem Fall Hero
.
Unten finden Sie einen Side-by-Side-Vergleich des gesamten Initialisierungsprozesses, des Hinzufügens von Methoden und der Vererbung einer Konstruktorfunktion und einer Klasse.
Obwohl die Syntax sehr unterschiedlich ist, ist das zugrunde liegende Ergebnis zwischen beiden Methoden fast gleich. Klassen geben uns eine prägnantere Möglichkeit, Objektbaupläne zu erstellen, und Konstruktorfunktionen beschreiben genauer, was unter der Haube passiert.
Schlussfolgerung
In diesem Tutorial haben wir die Ähnlichkeiten und Unterschiede zwischen JavaScript-Konstruktorfunktionen und ES6-Klassen kennengelernt. Sowohl Klassen als auch Konstruktoren imitieren ein objektorientiertes Vererbungsmodell für JavaScript, eine prototypbasierte Vererbungssprache.,
Das Verständnis der prototypischen Vererbung ist für einen effektiven JavaScript-Entwickler von größter Bedeutung. Die Kenntnis von Klassen ist äußerst hilfreich, da beliebte JavaScript-Bibliotheken wie React häufig die Syntax class
.