Ich lerne, wie man OOP mit JavaScript macht . Hat es das Schnittstellenkonzept (wie das von Java interface
)?
So könnte ich einen Listener erstellen ...
javascript
oop
Tom Brito
quelle
quelle
Antworten:
Es gibt keine Vorstellung von "diese Klasse muss diese Funktionen haben" (dh keine Schnittstellen an sich), weil:
Stattdessen verwendet JavaScript die sogenannte Ententypisierung . (Wenn es wie eine Ente läuft und wie eine Ente quakt, soweit es JS interessiert, ist es eine Ente.) Wenn Ihr Objekt die Methoden quack (), walk () und fly () hat, kann Code es verwenden, wo immer es erwartet Ein Objekt, das laufen, quaken und fliegen kann, ohne dass eine "Duckable" -Schnittstelle implementiert werden muss. Die Schnittstelle ist genau die Menge von Funktionen, die der Code verwendet (und die Rückgabewerte dieser Funktionen), und bei der Eingabe von Enten erhalten Sie diese kostenlos.
Das heißt nicht, dass Ihr Code nicht zur Hälfte ausfällt, wenn Sie versuchen anzurufen
some_dog.quack()
. Sie erhalten einen TypeError. Ehrlich gesagt, wenn Sie Hunden sagen, sie sollen quaken, haben Sie etwas größere Probleme. Das Tippen von Enten funktioniert am besten, wenn Sie sozusagen alle Ihre Enten hintereinander halten und Hunde und Enten nicht miteinander vermischen, es sei denn, Sie behandeln sie als generische Tiere. Mit anderen Worten, obwohl die Schnittstelle flüssig ist, ist sie immer noch da; Es ist oft ein Fehler, einen Hund an einen Code zu übergeben, der erwartet, dass er überhaupt quakt und fliegt.Wenn Sie jedoch sicher sind, dass Sie das Richtige tun, können Sie das Problem des Quacksalberhundes umgehen, indem Sie die Existenz einer bestimmten Methode testen, bevor Sie versuchen, sie anzuwenden. Etwas wie
So können Sie nach allen Methoden suchen, die Sie verwenden können, bevor Sie sie verwenden. Die Syntax ist allerdings etwas hässlich. Es gibt einen etwas schöneren Weg:
Dies ist Standard-JavaScript, daher sollte es in jedem JS-Interpreter funktionieren, der es wert ist, verwendet zu werden. Es hat den zusätzlichen Vorteil, wie Englisch zu lesen.
Für moderne Browser (dh so ziemlich jeden anderen Browser als IE 6-8) gibt es sogar eine Möglichkeit, zu verhindern, dass die Eigenschaft angezeigt wird in
for...in
:Das Problem ist, dass IE7-Objekte überhaupt keine haben
.defineProperty
und in IE8 angeblich nur auf Host-Objekten (dh DOM-Elementen und dergleichen) funktionieren. Wenn Kompatibilität ein Problem ist, können Sie nicht verwenden.defineProperty
. (Ich werde IE6 nicht einmal erwähnen, weil es außerhalb Chinas ziemlich irrelevant ist.)Ein weiteres Problem ist, dass einige Codierungsstile gerne davon ausgehen, dass jeder schlechten Code schreibt, und das Ändern verbieten,
Object.prototype
falls jemand blind verwenden möchtefor...in
. Wenn Sie sich dafür interessieren oder einen (IMO- defekten ) Code verwenden, versuchen Sie es mit einer etwas anderen Version:quelle
for...in
ist - und war schon immer - mit solchen Gefahren behaftet, und jeder, der dies tut, ohne zumindest zu berücksichtigen, dass jemand, der hinzugefügt wurdeObject.prototype
(eine nicht ungewöhnliche Technik, wie dieser Artikel selbst zugibt), sieht, dass sein Code in den Händen eines anderen bricht.for...in
Problem vermeiden . developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…for...in
Problem" bis zu einem gewissen Grad bestehen bleiben, denn es wird immer schlampigen Code geben ... nun ja, dasObject.defineProperty(obj, 'a', {writable: true, enumerable: false, value: 3});
ist viel mehr Arbeit als nurobj.a = 3;
. Ich kann Leute verstehen, die nicht öfter versuchen, es zu tun. : PHolen Sie sich eine Kopie von ' JavaScript Design Patterns ' von Dustin Diaz . Es gibt einige Kapitel, die sich mit der Implementierung von JavaScript-Schnittstellen durch Duck Typing befassen. Es ist auch eine schöne Lektüre. Aber nein, es gibt keine sprachliche Implementierung einer Schnittstelle, Sie müssen Duck Type .
quelle
In JavaScript (ECMAScript Edition 3) ist ein
implements
reserviertes Wort für die zukünftige Verwendung gespeichert . Ich denke, dies ist genau für diesen Zweck gedacht, aber in der Eile, die Spezifikation herauszubekommen, hatten sie keine Zeit zu definieren, was damit zu tun ist, so dass Browser derzeit nichts anderes tun Lassen Sie es dort sitzen und beschweren Sie sich gelegentlich, wenn Sie versuchen, es für etwas zu verwenden.Es ist möglich und in der Tat einfach genug, eine eigene
Object.implement(Interface)
Methode mit einer Logik zu erstellen , die immer dann funktioniert, wenn ein bestimmter Satz von Eigenschaften / Funktionen in einem bestimmten Objekt nicht implementiert ist.Ich habe einen Artikel über Objektorientierung geschrieben, in dem ich meine eigene Notation wie folgt verwende :
Es gibt viele Möglichkeiten, diese bestimmte Katze zu häuten, aber dies ist die Logik, die ich für meine eigene Schnittstellenimplementierung verwendet habe. Ich finde, ich bevorzuge diesen Ansatz und er ist leicht zu lesen und zu verwenden (wie Sie oben sehen können). Es bedeutet zwar, eine Implementierungsmethode hinzuzufügen, mit
Function.prototype
der einige Leute möglicherweise ein Problem haben, aber ich finde, dass sie wunderbar funktioniert.quelle
var interf = arguments[i]; for (prop in interf) { if (this.prototype[prop] === undefined) { throw 'Member [' + prop + '] missing from class definition.'; }}
. Siehe den Boden des Artikel - Link für ein aufwändigere Beispiel.JavaScript-Schnittstellen:
Obwohl JavaScript nicht über den
interface
Typ verfügt, wird es häufig benötigt. Aus Gründen, die sich auf die Dynamik von JavaScript und die Verwendung von Prototypical-Inheritance beziehen, ist es schwierig, konsistente Schnittstellen zwischen Klassen sicherzustellen. Dies ist jedoch möglich. und häufig emuliert.Zu diesem Zeitpunkt gibt es eine Handvoll besonderer Möglichkeiten, Schnittstellen in JavaScript zu emulieren. Varianz bei Ansätzen erfüllt normalerweise einige Bedürfnisse, während andere nicht angesprochen werden. Oft ist der robusteste Ansatz zu umständlich und behindert den Implementierer (Entwickler).
Hier ist ein Ansatz für Schnittstellen / abstrakte Klassen, der nicht sehr umständlich ist, erklärend ist, Implementierungen innerhalb von Abstraktionen auf ein Minimum beschränkt und genügend Raum für dynamische oder benutzerdefinierte Methoden lässt:
Teilnehmer
Gebotsauflöser
Die
resolvePrecept
Funktion ist eine Dienstprogramm- und Hilfsfunktion, die Sie in Ihrer Abstract-Klasse verwenden können . Seine Aufgabe ist es, eine angepasste Implementierungsbehandlung von gekapselten Vorschriften (Daten und Verhalten) zu ermöglichen . Es kann Fehler auslösen oder warnen - UND - der Implementor-Klasse einen Standardwert zuweisen.iAbstractClass
Das
iAbstractClass
definiert die zu verwendende Schnittstelle. Sein Ansatz beinhaltet eine stillschweigende Vereinbarung mit seiner Implementiererklasse. Diese Schnittstelle weist jedem Gebot genau das gleiche Gebots-Namespace (OR) zu, unabhängig davon, was die Funktion Precept Resolver zurückgibt. Die stillschweigende Vereinbarung wird jedoch in einen Kontext aufgelöst - eine Bestimmung des Implementierers.Implementierer
Der Implementierer 'stimmt' einfach mit einer Schnittstelle ( in diesem Fall iAbstractClass ) überein und wendet sie mithilfe von Constructor-Hijacking an :
iAbstractClass.apply(this)
. Indem wir die oben genannten Daten und Verhaltensweisen definieren und dann den Konstruktor der Schnittstelle entführen und den Kontext des Implementierers an den Schnittstellenkonstruktor übergeben, können wir sicherstellen, dass die Überschreibungen des Implementierers hinzugefügt werden und dass die Schnittstelle Warnungen und Standardwerte erläutert.Dies ist ein sehr umständlicher Ansatz, der meinem Team und mir im Laufe der Zeit und bei verschiedenen Projekten sehr gute Dienste geleistet hat. Es hat jedoch einige Vorbehalte und Nachteile.
Nachteile
Dies hilft zwar dabei, die Konsistenz in Ihrer Software in erheblichem Maße zu implementieren, implementiert jedoch keine echten Schnittstellen, sondern emuliert sie. Obwohl Definitionen, Standardwerte und Warnungen oder Fehler sind expliziert wird die Erklärung der Verwendung erzwungen und behauptete durch den Entwickler (wie bei viel von JavaScript - Entwicklung).
Dies ist anscheinend der beste Ansatz für "Schnittstellen in JavaScript" . Ich würde jedoch gerne Folgendes lösen:
delete
Aktionen einfrierenTrotzdem hoffe ich, dass dies Ihnen genauso hilft wie meinem Team und mir.
quelle
Sie benötigen Schnittstellen in Java, da diese statisch typisiert sind und der Vertrag zwischen Klassen während der Kompilierung bekannt sein sollte. In JavaScript ist das anders. JavaScript wird dynamisch eingegeben. Wenn Sie das Objekt erhalten, können Sie einfach überprüfen, ob es eine bestimmte Methode hat, und es aufrufen.
quelle
yourMethod
Eintrag Nr. 5 in derSuperclass
vtable eingefügt, und für jede eigene Unterklasse wirdyourMethod
einfach auf Eintrag Nr. 5 dieser Unterklasse verwiesen bei der entsprechenden Umsetzung.Implementation
implementiertSomeInterface
nicht nur, dass sie die gesamte Schnittstelle implementiert. Es enthält Informationen mit der Aufschrift "Ich implementiereSomeInterface.yourMethod
" und verweist auf die Methodendefinition fürImplementation.yourMethod
. Wenn die JVM aufruftSomeInterface.yourMethod
, sucht sie in der Klasse nach Informationen zu Implementierungen der Methode dieser Schnittstelle und stellt fest, dass sie aufgerufen werden mussImplementation.yourMethod
.Hoffe, dass jeder, der noch nach einer Antwort sucht, diese hilfreich findet.
Sie können es mit einem Proxy ausprobieren (seit ECMAScript 2015 Standard): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Dann kann man leicht sagen:
quelle
Wenn Sie einen Transcompiler verwenden möchten, können Sie TypeScript ausprobieren. Es unterstützt Entwürfe von ECMA-Funktionen (im Vorschlag werden Schnittstellen als " Protokolle " bezeichnet), ähnlich wie Sprachen wie Coffeescript oder Babel.
In TypeScript kann Ihre Benutzeroberfläche folgendermaßen aussehen:
Was du nicht kannst:
quelle
In JavaScript gibt es keine nativen Schnittstellen. Es gibt verschiedene Möglichkeiten, eine Schnittstelle zu simulieren. Ich habe ein Paket geschrieben, das es tut
Sie können die Implantation hier sehen
quelle
Javascript hat keine Schnittstellen. Aber es kann vom Typ Ente sein, ein Beispiel finden Sie hier:
http://reinsbrain.blogspot.com/2008/10/interface-in-javascript.html
quelle
Ich weiß, dass dies eine alte ist, aber ich habe in letzter Zeit immer mehr gebraucht, um eine praktische API zum Überprüfen von Objekten anhand von Schnittstellen zu haben. Also schrieb ich Folgendes: https://github.com/tomhicks/methodical
Es ist auch über NPM erhältlich:
npm install methodical
Es macht im Grunde alles, was oben vorgeschlagen wurde, mit einigen Optionen, um etwas strenger zu sein, und alles ohne jede Menge
if (typeof x.method === 'function')
Boilerplate zu tun .Hoffentlich findet es jemand nützlich.
quelle
Dies ist eine alte Frage, dennoch nervt mich dieses Thema immer wieder.
Da sich viele der Antworten hier und im Internet auf die "Durchsetzung" der Benutzeroberfläche konzentrieren, möchte ich eine alternative Ansicht vorschlagen:
Zum Beispiel habe ich einen E-Mail-Generator , der erwartet, E-Mail-Abschnittsfabriken zu erhalten , die "wissen", wie der Inhalt und das HTML der Abschnitte generiert werden. Daher müssen sie alle eine Art
getContent(id)
undgetHtml(content)
Methoden haben.Die größte Herausforderung bei diesem Muster besteht darin, dass die Methoden entweder
static
die Instanz selbst sein oder als Argument erhalten müssen, um auf ihre Eigenschaften zugreifen zu können. Es gibt jedoch Fälle, in denen ich finde, dass dieser Kompromiss den Aufwand wert ist.quelle
abstrakte Schnittstelle wie diese
Erstellen Sie eine Instanz:
und benutze es
quelle