Hat JavaScript den Schnittstellentyp (z. B. Javas 'Schnittstelle')?

Antworten:

648

Es gibt keine Vorstellung von "diese Klasse muss diese Funktionen haben" (dh keine Schnittstellen an sich), weil:

  1. Die JavaScript-Vererbung basiert auf Objekten, nicht auf Klassen. Das ist keine große Sache, bis Sie erkennen:
  2. JavaScript ist eine extrem dynamisch typisierte Sprache. Sie können ein Objekt mit den richtigen Methoden erstellen, um es an die Benutzeroberfläche anzupassen, und dann alle Elemente aufheben, die es angepasst haben . Es wäre so einfach, das Typensystem zu untergraben - auch aus Versehen! - dass es sich nicht lohnen würde, überhaupt ein Typensystem zu erstellen.

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

if (typeof(someObject.quack) == "function")
{
    // This thing can quack
}

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:

Object.prototype.can = function(methodName)
{
     return ((typeof this[methodName]) == "function");
};

if (someObject.can("quack"))
{
    someObject.quack();
}

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:

Object.defineProperty(Object.prototype, 'can', {
    enumerable: false,
    value: function(method) {
        return (typeof this[method] === 'function');
    }
}

Das Problem ist, dass IE7-Objekte überhaupt keine haben .definePropertyund 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.prototypefalls jemand blind verwenden möchte for...in. Wenn Sie sich dafür interessieren oder einen (IMO- defekten ) Code verwenden, versuchen Sie es mit einer etwas anderen Version:

function can(obj, methodName)
{
     return ((typeof obj[methodName]) == "function");
}

if (can(someObject, "quack"))
{
    someObject.quack();
}
cHao
quelle
7
Es ist nicht so schrecklich, wie es sich herausstellt. for...inist - und war schon immer - mit solchen Gefahren behaftet, und jeder, der dies tut, ohne zumindest zu berücksichtigen, dass jemand, der hinzugefügt wurde Object.prototype(eine nicht ungewöhnliche Technik, wie dieser Artikel selbst zugibt), sieht, dass sein Code in den Händen eines anderen bricht.
CHao
1
@entonio: Ich würde die Formbarkeit der eingebauten Typen eher als Merkmal als als Problem betrachten. Es ist ein großer Teil dessen, was Shims / Polyfills möglich macht. Ohne sie würden wir entweder alle integrierten Typen mit möglicherweise inkompatiblen Untertypen umschließen oder auf die universelle Browserunterstützung warten (die möglicherweise nie eintreten wird, wenn Browser keine Inhalte unterstützen, weil die Leute sie nicht verwenden, weil die Browser sie nicht verwenden. nicht unterstützen). Da die integrierten Typen geändert werden können, können wir stattdessen nur viele der Funktionen hinzufügen, die noch nicht vorhanden sind.
CHao
1
In der letzten Version von Javascript (1.8.5) können Sie die Eigenschaft eines Objekts als nicht aufzählbar definieren. Auf diese Weise können Sie das for...inProblem vermeiden . developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Tomas Prado
1
@ Tomás: Leider müssen wir uns über solche Dinge noch Gedanken machen, bis jeder Browser etwas mit ES5 kompatibles ausführt. Und selbst dann wird das " for...inProblem" bis zu einem gewissen Grad bestehen bleiben, denn es wird immer schlampigen Code geben ... nun ja, das Object.defineProperty(obj, 'a', {writable: true, enumerable: false, value: 3});ist viel mehr Arbeit als nur obj.a = 3;. Ich kann Leute verstehen, die nicht öfter versuchen, es zu tun. : P
cHao
1
Hehe ... liebe das "Ehrlich gesagt, wenn du Hunden sagst, sie sollen quaken, hast du etwas größere Probleme. Eine großartige Analogie, um zu zeigen, dass Sprachen nicht versuchen sollten, Dummheit zu vermeiden. Das ist immer ein verlorener Kampf. -Scott
Skooppa. com
72

Holen 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 .

// example duck typing method
var hasMethods = function(obj /*, method list as strings */){
    var i = 1, methodName;
    while((methodName = arguments[i++])){
        if(typeof obj[methodName] != 'function') {
            return false;
        }
    }
    return true;
}

// in your code
if(hasMethods(obj, 'quak', 'flapWings','waggle')) {
    //  IT'S A DUCK, do your duck thang
}
BGerrissen
quelle
Die im Buch "Pro Javascript Design Patterns" beschriebene Methode ist wahrscheinlich der beste Ansatz für eine Reihe von Dingen, die ich hier und von dem, was ich versucht habe, gelesen habe. Darüber hinaus können Sie die Vererbung verwenden, wodurch es noch besser ist, OOP-Konzepten zu folgen. Einige mögen behaupten, dass Sie in JS keine OOP-Konzepte benötigen, aber ich bin anderer Meinung.
animageofmine
21

In JavaScript (ECMAScript Edition 3) ist ein implementsreserviertes 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 :

// Create a 'Dog' class that inherits from 'Animal'
// and implements the 'Mammal' interface
var Dog = Object.extend(Animal, {
    constructor: function(name) {
        Dog.superClass.call(this, name);
    },
    bark: function() {
        alert('woof');
    }
}).implement(Mammal);

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.prototypeder einige Leute möglicherweise ein Problem haben, aber ich finde, dass sie wunderbar funktioniert.

Function.prototype.implement = function() {
    // Loop through each interface passed in and then check 
    // that its members are implemented in the context object (this).
    for(var i = 0; i < arguments.length; i++) {
       // .. Check member's logic ..
    }
    // Remember to return the class being tested
    return this;
}
Steven de Salas
quelle
4
Diese Syntax tut meinem Gehirn wirklich weh, aber die Implementierung hier ist ziemlich interessant.
Cypher
2
Javascript muss dies tun (was das Gehirn verletzt), insbesondere wenn es aus saubereren OO-Sprachimplementierungen stammt.
Steven de Salas
10
@StevendeSalas: Eh. JS ist in der Regel ziemlich sauber, wenn Sie aufhören, es als klassenorientierte Sprache zu behandeln. Der ganze Mist, der benötigt wird, um Klassen, Schnittstellen usw. zu emulieren ... das wird dein Gehirn wirklich verletzen. Prototypen? Wirklich einfaches Zeug, wenn Sie aufhören, gegen sie zu kämpfen.
CHao
Was ist in "// .. Überprüfen Sie die Logik des Mitglieds." ? wie sieht das aus
PositiveGuy
Hallo @We, das Überprüfen der Mitgliederlogik bedeutet, die gewünschten Eigenschaften zu durchlaufen und einen Fehler auszulösen, wenn einer fehlt. Etwas in der Art von 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.
Steven de Salas
12

JavaScript-Schnittstellen:

Obwohl JavaScript nicht über den interfaceTyp 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:

function resolvePrecept(interfaceName) {
    var interfaceName = interfaceName;
    return function curry(value) {
        /*      throw new Error(interfaceName + ' requires an implementation for ...');     */
        console.warn('%s requires an implementation for ...', interfaceName);
        return value;
    };
}

var iAbstractClass = function AbstractClass() {
    var defaultTo = resolvePrecept('iAbstractClass');

    this.datum1 = this.datum1 || defaultTo(new Number());
    this.datum2 = this.datum2 || defaultTo(new String());

    this.method1 = this.method1 || defaultTo(new Function('return new Boolean();'));
    this.method2 = this.method2 || defaultTo(new Function('return new Object();'));

};

var ConcreteImplementation = function ConcreteImplementation() {

    this.datum1 = 1;
    this.datum2 = 'str';

    this.method1 = function method1() {
        return true;
    };
    this.method2 = function method2() {
        return {};
    };

    //Applies Interface (Implement iAbstractClass Interface)
    iAbstractClass.apply(this);  // .call / .apply after precept definitions
};

Teilnehmer

Gebotsauflöser

Die resolvePreceptFunktion 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 iAbstractClassdefiniert 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:

  • Behauptungen von Rückgabetypen
  • Behauptungen von Unterschriften
  • Objekte aus deleteAktionen einfrieren
  • Behauptungen über alles andere, was in der Spezifität der JavaScript-Community vorherrscht oder benötigt wird

Trotzdem hoffe ich, dass dies Ihnen genauso hilft wie meinem Team und mir.

Cody
quelle
7

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.

Alex Reitbort
quelle
1
Tatsächlich benötigen Sie keine Schnittstellen in Java. Es ist ausfallsicher, sicherzustellen, dass Objekte über eine bestimmte API verfügen, damit Sie sie gegen andere Implementierungen austauschen können.
BGerrissen
3
Nein, sie werden tatsächlich in Java benötigt, damit vtables für Klassen erstellt werden können, die zur Kompilierungszeit eine Schnittstelle implementieren. Wenn Sie deklarieren, dass eine Klasse eine Schnittstelle implementiert, wird der Compiler angewiesen, eine kleine Struktur zu erstellen, die Zeiger auf alle von dieser Schnittstelle benötigten Methoden enthält. Andernfalls müsste es zur Laufzeit nach Namen versendet werden (wie dies bei dynamisch typisierten Sprachen der Fall ist).
herrlicher
Ich denke nicht, dass das richtig ist. Der Versand ist in Java immer dynamisch (es sei denn, eine Methode ist endgültig), und die Tatsache, dass die Methode zu einer Schnittstelle gehört, ändert nichts an den Suchregeln. Der Grund, warum Schnittstellen in statisch typisierten Sprachen benötigt werden, besteht darin, dass Sie denselben Pseudotyp (die Schnittstelle) verwenden können, um auf nicht verwandte Klassen zu verweisen.
Entonio
2
@entonio: Der Versand ist nicht so dynamisch wie er aussieht. Die eigentliche Methode ist aufgrund des Polymorphismus oft bis zur Laufzeit nicht bekannt, aber der Bytecode sagt nicht "invoke yourMethod"; Es heißt "Superclass.yourMethod aufrufen". Die JVM kann eine Methode nicht aufrufen, ohne zu wissen, in welcher Klasse sie gesucht werden soll . Während der Verknüpfung wird möglicherweise yourMethodEintrag Nr. 5 in der Superclassvtable eingefügt, und für jede eigene Unterklasse wird yourMethodeinfach auf Eintrag Nr. 5 dieser Unterklasse verwiesen bei der entsprechenden Umsetzung.
CHao
1
@entonio: Für Schnittstellen, Regeln Sie ein wenig ändern. (Nicht sprachlich, aber der generierte Bytecode und der Suchprozess der JVM sind unterschiedlich.) Eine Klasse mit dem Namen Implementationimplementiert SomeInterfacenicht nur, dass sie die gesamte Schnittstelle implementiert. Es enthält Informationen mit der Aufschrift "Ich implementiere SomeInterface.yourMethod" und verweist auf die Methodendefinition für Implementation.yourMethod. Wenn die JVM aufruft SomeInterface.yourMethod, sucht sie in der Klasse nach Informationen zu Implementierungen der Methode dieser Schnittstelle und stellt fest, dass sie aufgerufen werden muss Implementation.yourMethod.
CHao
6

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

latLngLiteral = new Proxy({},{
    set: function(obj, prop, val) {
        //only these two properties can be set
        if(['lng','lat'].indexOf(prop) == -1) {
            throw new ReferenceError('Key must be "lat" or "lng"!');
        }

        //the dec format only accepts numbers
        if(typeof val !== 'number') {
            throw new TypeError('Value must be numeric');
        }

        //latitude is in range between 0 and 90
        if(prop == 'lat'  && !(0 < val && val < 90)) {
            throw new RangeError('Position is out of range!');
        }
        //longitude is in range between 0 and 180
        else if(prop == 'lng' && !(0 < val && val < 180)) {
            throw new RangeError('Position is out of range!');
        }

        obj[prop] = val;

        return true;
    }
});

Dann kann man leicht sagen:

myMap = {}
myMap.position = latLngLiteral;
shaedrich
quelle
5

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:

interface IMyInterface {
    id: number; // TypeScript types are lowercase
    name: string;
    callback: (key: string; value: any; array: string[]) => void;
    type: "test" | "notATest"; // so called "union type"
}

Was du nicht kannst:

shaedrich
quelle
3

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

Amit Wagner
quelle
2

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

Reinsbrain
quelle
Ich mag das Muster, das der Artikel unter diesem Link verwendet, um Aussagen über den Typ zu machen. Ein Fehler, der ausgelöst wird, wenn etwas die beabsichtigte Methode nicht implementiert, ist genau das, was ich erwarten würde, und ich mag es, wie ich diese erforderlichen Methoden (wie eine Schnittstelle) gruppieren kann, wenn ich es auf diese Weise mache.
Eric Dubé
1
Ich hasse es zu transpilieren (und Quellkarten zum Debuggen), aber Typescript ist so nah an ES6, dass ich dazu neige, meine Nase zu halten und in Typescript einzutauchen. ES6 / Typescript ist interessant, da Sie beim Definieren einer Schnittstelle (Verhalten) neben Methoden auch Eigenschaften einbeziehen können.
Reinsbrain
1

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.

Tom
quelle
Tom, ich habe gerade ein AngularJS TDD-Video gesehen und wenn er ein Framework installiert, ist eines der abhängigen Pakete Ihr methodisches Paket! Gut gemacht!
Cody
Haha ausgezeichnet. Ich habe es im Grunde genommen aufgegeben, nachdem die Leute bei der Arbeit davon überzeugt waren, dass Schnittstellen in JavaScript ein No-Go waren. Vor kurzem hatte ich eine Idee zu einer Bibliothek, die im Grunde genommen ein Objekt als Proxy verwendet, um sicherzustellen, dass nur bestimmte Methoden verwendet werden, was im Grunde genommen eine Schnittstelle ist. Ich denke immer noch, dass Schnittstellen einen Platz in JavaScript haben! Kannst du das Video übrigens verlinken? Ich würde gerne einen Blick darauf werfen.
Tom
Wetten, Tom? Ich werde versuchen, es bald zu finden. Auch die Anekdote über Schnittstellen als Proxys. Prost!
Cody
1

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:

Ich spüre am meisten den Mangel an Schnittstellen, wenn ich mehrere Klassen verwende, die sich ähnlich verhalten (dh eine Schnittstelle implementieren ).

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)und getHtml(content)Methoden haben.

Das Muster, das den Schnittstellen am nächsten kommt (obwohl es immer noch eine Problemumgehung ist), ist die Verwendung einer Klasse, die zwei Argumente erhält, die die beiden Schnittstellenmethoden definieren.

Die größte Herausforderung bei diesem Muster besteht darin, dass die Methoden entweder staticdie 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.

class Filterable {
  constructor(data, { filter, toString }) {
    this.data = data;
    this.filter = filter;
    this.toString = toString;
    // You can also enforce here an Iterable interface, for example,
    // which feels much more natural than having an external check
  }
}

const evenNumbersList = new Filterable(
  [1, 2, 3, 4, 5, 6], {
    filter: (lst) => {
      const evenElements = lst.data.filter(x => x % 2 === 0);
      lst.data = evenElements;
    },
    toString: lst => `< ${lst.data.toString()} >`,
  }
);

console.log('The whole list:    ', evenNumbersList.toString(evenNumbersList));
evenNumbersList.filter(evenNumbersList);
console.log('The filtered list: ', evenNumbersList.toString(evenNumbersList));

GalAbra
quelle
0

abstrakte Schnittstelle wie diese

const MyInterface = {
  serialize: () => {throw "must implement serialize for MyInterface types"},
  print: () => console.log(this.serialize())
}

Erstellen Sie eine Instanz:

function MyType() {
  this.serialize = () => "serialized "
}
MyType.prototype = MyInterface

und benutze es

let x = new MyType()
x.print()
Kevin Krausse
quelle