Welcome to Our Website

JavaScript Factory Functions vs Constructor Functions vs Classes (Deutsch)

Vor ES6 gab es viele Verwirrung über die Unterschiede zwischen einer Factory-Funktion und einer Konstruktorfunktion in JavaScript. Da ES6 das Schlüsselwort `class` hat, scheinen viele Leute zu denken, dass es viele Probleme mit Konstruktorfunktionen gelöst hat. Lassen Sie uns die Hauptunterschiede untersuchen, die Sie noch kennen müssen.,

Schauen wir uns zunächst Beispiele an:

Jede dieser Strategien speichert Methoden in einem gemeinsam genutzten Prototyp und unterstützt optional private Daten über Konstruktorfunktionsschließungen. Mit anderen Worten, sie haben meist die gleichen Eigenschaften und könnten meist austauschbar verwendet werden.

In JavaScript kann jede Funktion ein neues Objekt zurückgeben. Wenn es sich nicht um eine Konstruktorfunktion oder-klasse handelt, wird sie als Factory-Funktion bezeichnet.,

ES6 klassen desugar zu konstruktor funktionen, so alles, was folgt über konstruktor funktionen gilt auch für ES6 klassen:

class Foo {}console.log(typeof Foo); // function

Konstruktoren kraft anrufer zu verwenden die new schlüsselwort. Das ist es, aber das hat einige relevante Nebenwirkungen.

Was macht das Schlüsselwort new?,

Hinweis: Wir verwenden instance, um auf die neu erstellte Instanz zu verweisen, und Constructor, um auf die Konstruktorfunktion oder-klasse zu verweisen, die die Instanz erstellt hat.

  1. Instanziiert ein neues Instanzobjekt und bindet this innerhalb des Konstruktors daran.
  2. Bindet instance.__proto__ an Constructor.prototype.
  3. Als Nebeneffekt von 2 bindet instance.__proto__.constructor an Constructor.,
  4. gibt implizit this zurück, was sich auf instancebezieht.

Vorteile von Konstruktoren & `class`

  • In den meisten Büchern lernen Sie, Klassen oder Konstruktoren zu verwenden.
  • this bezieht sich auf das neue Objekt.
  • Manche Leute mögen die Art und Weise myFoo = new Foo() liest.
  • Es kann einen Leistungsvorteil bei der Mikrooptimierung geben, aber Sie sollten sich darüber keine Sorgen machen, es sei denn, Sie haben Ihren Code profiliert und bewiesen, dass dies ein Problem für Sie ist.,

Nachteile von Konstruktoren & `class`

Vor ES6 war das Vergessen von new ein sehr häufiger Fehler. Um dem entgegenzuwirken, haben viele Leute boilerplate verwendet, um es zu erzwingen:

function Foo() {
if (!(this instanceof Foo)) { return new Foo(); }
}

In ES6+ (ES2015) Wenn Sie versuchen, einen Klassenkonstruktor ohne new aufzurufen, wird immer ein Fehler ausgegeben. Es ist nicht möglich zu vermeiden, die new – Anforderung für Aufrufer zu erzwingen, ohne Ihre Klasse in eine Factory-Funktion einzuschließen.,

Details der Instanziierung werden in die aufrufende API durchgesickert (über die Anforderung „neu“).

Alle Aufrufer sind eng an die Konstruktorimplementierung gekoppelt. Wenn Sie jemals die zusätzliche Flexibilität des Werks benötigen, ist der Refactor eine grundlegende Änderung. Klasse Fabrik refactors sind Häufig genug, dass Sie erscheinen in der Samenflüssigkeit Refactoring Buch „Refactoring: Improving the Design of existing Code“ von Martin Fowler, Kent Beck, John Brant, William Opdyke und Don Roberts.,

Konstruktoren brechen das Open / Closed-Prinzip

Aufgrund der new – Anforderung verletzen Konstruktorfunktionen das Open / Closed-Prinzip: Eine API sollte zur Erweiterung geöffnet, aber zur Änderung geschlossen sein.

Ich argumentiere, dass die Klasse zu Factory Refactor üblich genug ist, dass sie als Standarderweiterung für alle Konstruktoren betrachtet werden sollte: Ein Upgrade von einer Klasse zu einer Factory sollte keine Dinge kaputt machen, aber in JavaScript tut es das.,

Wenn Sie mit dem Exportieren eines Konstruktors oder einer Klasse beginnen und Benutzer den Konstruktor verwenden, stellen Sie fest, dass Sie die Flexibilität einer Factory benötigen (z. B. um die Implementierung auf Objektpools umzustellen oder über Ausführungskontexte hinweg zu instanziieren oder um mehr Vererbungsflexibilität mit alternativen Prototypen zu erzielen), können Sie dies nicht einfach tun, ohne einen Refaktor für Aufrufer zu erzwingen.,

Leider ist in JavaScript der Wechsel von einem Konstruktor oder einer Klasse zu einer Fabrik eine grundlegende Änderung:

Im obigen Beispiel beginnen wir mit einer Klasse, aber wir möchten die Möglichkeit hinzufügen, verschiedene Arten von Auto-Bundles anzubieten. Dazu verwendet das Werk alternative Prototypen für verschiedene Fahrzeugbündel. Ich habe diese Technik verwendet, um verschiedene Implementierungen einer Media Player-Schnittstelle zu speichern und den richtigen Prototyp basierend auf dem Medientyp auszuwählen, den der Player steuern musste.,

Die Verwendung von Konstruktoren ermöglicht das trügerische ‚instanceof‘

Eine der wichtigsten Änderungen im Konstruktor an factory refactor ist instanceof. Manchmal sind Leute versucht, instanceof als Typprüfschutz in ihrem Code zu verwenden. Das kann sehr problematisch sein. Ich empfehle Ihnen, instanceofzu vermeiden.

`instanceof` liegt.,

instanceof führt keine Typprüfung so durch, wie Sie ähnliche Überprüfungen in stark typisierten Sprachen erwarten. Stattdessen wird eine Identitätsprüfung durchgeführt, bei der das __proto__ – Objekt des Objekts mit der Constructor.prototype – Eigenschaft verglichen wird.

Es funktioniert nicht über verschiedene Speicherbereiche wie Iframes hinweg, zum Beispiel (eine häufige Fehlerquelle in JavaScript-Einbettungen von Drittanbietern). Es funktioniert auch nicht, wenn Ihre Constructor.prototype ersetzt wird.,

Es schlägt auch fehl, wenn Sie mit einer Klasse oder einem Konstruktor beginnen (der this zurückgibt, der mit der Constructor.prototype verknüpft ist) und dann zum Exportieren eines beliebigen Objekts wechseln (nicht verknüpft mit der Constructor.prototype), was passiert, wenn Sie von einem Konstruktor zu einer Fabrik wechseln.

Kurz gesagt, instanceof ist eine weitere Möglichkeit, von einem Konstruktor zu einer Factory zu wechseln.

Vorteile der Verwendung der Klasse

  • Bequeme, in sich geschlossene Syntax.,
  • Eine einzige, kanonische Möglichkeit, Klassen in JavaScript zu emulieren. Vor ES6, gab es mehrere konkurrierende Implementierungen in gängigen Bibliotheken.
  • Mehr vertraut mit Menschen aus einem klassenbasierten Sprachhintergrund.

Nachteile der Verwendung der Klasse

Alle Konstruktornachteile sowie:

  • Versuchung für Benutzer, problematische Klassenhierarchien mit dem Schlüsselwort extends zu erstellen.,

Klassenhierarchien führen zu einer Reihe bekannter Probleme im objektorientierten Design, einschließlich des fragilen Basisklassenproblems, des Gorilla-Bananenproblems, des Duplizierungsproblems durch Notwendigkeit und so weiter. Leider bietet Klasse erstreckt sich wie Bälle leisten werfen und Stühle leisten Sitzen. Lesen Sie dazu „Die beiden Säulen von JavaScript: Prototypal OO“ und „Inside the Dev Team Death Spiral“.,

Es ist erwähnenswert, dass sowohl Konstruktoren als auch Fabriken auch zum Erstellen problematischer Vererbungshierarchien verwendet werden können, aber mit dem Schlüsselwort `extends` erstellt class eine Erschwinglichkeit, die Sie auf den falschen Weg führt. Mit anderen Worten, es ermutigt Sie, in Bezug auf unflexible (und oft falsche) Is-a-Beziehungen zu denken, anstatt die flexibleren kompositorischen Has-a-oder Can-Do-Beziehungen.

Eine Affordance ist eine Funktion, die die Möglichkeit bietet, eine bestimmte Aktion auszuführen., Zum Beispiel ermöglicht ein Knopf das Verdrehen, ein Hebel das Ziehen, ein Knopf das Drücken usw.

Die Vorteile der Verwendung von Fabriken

Fabriken sind viel flexibler als Konstruktorfunktionen oder Klassen und führen die Menschen nicht auf den falschen Weg, indem sie sie mit dem Schlüsselwort „extends“ und tiefen Vererbungshierarchien verführen. Es gibt viele sicherere Mechanismen zur Wiederverwendung von Code, die Sie gegenüber der Klassenvererbung bevorzugen sollten, einschließlich Funktionen und Modulen.,

Geben Sie ein beliebiges Objekt zurück und verwenden Sie einen beliebigen Prototyp

Sie können beispielsweise problemlos verschiedene Arten von Objekten erstellen, die dieselbe API implementieren, z. B. einen Media Player, der Player für mehrere instanziieren kann Arten von Videoinhalten, die verschiedene APIs unter der Haube verwenden, oder eine Ereignisbibliothek, die DOM-Ereignisse oder Web-Socket-Ereignisse ausgeben kann.

Fabriken können Objekte auch über Ausführungskontexte hinweg instanziieren, Objektpools nutzen und flexiblere prototypische Vererbungsmodelle ermöglichen.,

Keine Refactoring Sorgen

Sie würden nie eine Notwendigkeit haben, von einer Fabrik zu einem Konstruktor zu konvertieren, so Refactoring wird nie ein Problem sein.

Keine `neuen`

Keine Zweideutigkeit über die Verwendung von new. (Dadurch verhält sich this schlecht, siehe nächsten Punkt).

Standard` dieses ‚Verhalten

this verhält sich wie gewohnt, sodass Sie damit auf das übergeordnete Objekt zugreifen können. Zum Beispiel bezieht sichplayer.create(),this auf player, genau wie jeder andere Methodenaufruf., call() und apply() weisen Sie auch this erwartungsgemäß neu zu.

Manche Leute mögen die Art und Weise, wie` MyFoo = createFoo () ‚ liest

  • Erstellt keinen Link von der Instanz zu Factory.prototype — aber das ist eigentlich eine gute Sache, weil Sie keine trügerische instanceof. Stattdessen schlägt instanceof immer fehl. Siehe Vorteile.
  • this bezieht sich nicht auf das neue Objekt in der Fabrik. Siehe Vorteile.,
  • Es kann langsamer als eine Konstruktorfunktion in Mikrooptimierungs-Benchmarks ausführen. Der langsame Weg ist immer noch sehr schnell Millionen von ops/sec auf einem alten computer. Dies ist eher ein Problem im Bibliotheks – oder Framework-Code als im Anwendungscode. Benchmark immer aus der Benutzerperspektive, bevor Mikrooptimierungen verwendet werden.

Schlussfolgerung

Meiner Meinung nach hat class möglicherweise eine bequeme Syntax, aber das kann die Tatsache nicht ausgleichen, dass es unvorsichtige Benutzer dazu bringt, auf den Felsen der Klassenvererbung zum Absturz zu bringen., Es ist auch riskant, da Sie in Zukunft möglicherweise ein Upgrade auf eine Factory durchführen möchten, aber alle Ihre Aufrufer aufgrund des Schlüsselworts new eng mit der Konstruktorfunktion verbunden sind und die Tatsache, dass der Wechsel von Klassen zu Fabriken eine wichtige Änderung darstellt.

Sie denken vielleicht, dass Sie die Aufrufseiten einfach umgestalten können, aber in großen Teams oder wenn die Klasse, mit der Sie arbeiten, Teil einer öffentlichen API ist, können Sie Code brechen, der nicht in Ihrer Kontrolle ist. Mit anderen Worten, Sie können nicht immer davon ausgehen, dass Refactoring-Anrufer sogar eine Option sind.,

Das Coole an Fabriken ist, dass sie nicht nur leistungsfähiger und flexibler sind, sondern auch die einfachste Möglichkeit, ganze Teams und ganze API-Benutzerbasen zu ermutigen, Muster zu verwenden, die einfach, flexibel und sicher sind.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.