Frage

Wie kann ich Züge in JavaScript implementieren?

War es hilfreich?

Lösung

function Trait (methods) {
  this.traits = [methods];
};

Trait.prototype = {
    constructor: Trait

  , uses: function (trait) {
      this.traits = this.traits.concat (trait.traits);
      return this;
    }

  , useBy: function (obj) {
      for (var i = 0; i < this.traits.length; ++i) {
        var methods = this.traits [i];
        for (var prop in methods) {
          if (methods.hasOwnProperty (prop)) {
            obj [prop] = obj [prop] || methods [prop];
          }
        }
      }
    }
};

Trait.unimplemented = function (obj, traitName) {
  if (obj === undefined || traitName === undefined) {
    throw new Error ("Unimplemented trait property.");
  }
  throw new Error (traitName + " is not implemented for " + obj);
};

Beispiel:

var TEq = new Trait ({
    equalTo: function (x) {
      Trait.unimplemented (this, "equalTo");
    }

  , notEqualTo: function (x) {
      return !this.equalTo (x);
    }
});

var TOrd = new Trait ({
    lessThan: function (x) {
      Trait.unimplemented (this, "lessThan");
    }

  , greaterThan: function (x) {
      return !this.lessThanOrEqualTo (x);
    }

  , lessThanOrEqualTo: function (x) {
      return this.lessThan (x) || this.equalTo (x);
    }

  , greaterThanOrEqualTo: function (x) {
      return !this.lessThan (x);
    }
}).uses (TEq);


function Rational (numerator, denominator) {
  if (denominator < 0) {
    numerator *= -1;
    denominator *= -1;
  }
  this.numerator = numerator;
  this.denominator = denominator;
}

Rational.prototype = {
    constructor: Rational

  , equalTo: function (q) {
      return this.numerator * q.numerator === this.denominator * q.denominator;
    }

  , lessThan: function (q) {
      return this.numerator * q.denominator < q.numerator * this.denominator;
    }
};

TOrd.useBy (Rational.prototype);

var x = new Rational (1, 5);
var y = new Rational (1, 2);

[x.notEqualTo (y), x.lessThan (y)]; // [true, true]

Andere Tipps

Es gibt verschiedene Ansätze und in der Zwischenzeit der Produktion bereit Bibliotheken als auch.

Mixins sind die älteste Form der Wiederverwendung von Code über Klassenhierarchien. Sie müssen in linearer Reihenfolge zusammengesetzt werden, da das Konzept des Mixins nicht Abdeckung / erkennt Konfliktlösung Funktionalität.

Traits sind feinkörnig Einheiten der Wiederverwendung von Code, dass die Arbeit auf Klassenebene zu; aber sie sind flexibler, da Traits Zusammensetzung Operatoren für die Kombination, Ausschluss oder Aliasing von Methoden zur Verfügung stellen müssen.

Ich empfehle zwei Papiere zu lesen sowohl eine Bibliothek Agnostiker reine Funktion basierte Konzept zu begegnen, sind für Mixins / Traits / Talent.

  1. Ein neuer Blick auf JavaScript Mixins von Angus Croll ab Mai 2011
  2. Die vielen Talente JavaScript für die Programmierung verallgemeinern Rollenorientierte Ansätze wie Traits und Mixins ab April 2014.

Die reine Funktion und Delegation basierte mixin Mechanik ist so einfach wie mit den nächsten 2 angegebenen Beispielen zur Verfügung gestellt ...

var Enumerable_first = function () {
  this.first = function () {
    return this[0];
  };
};
var list = ["foo", "bar", "baz"];

console.log("(typeof list.first)", (typeof list.first)); // "undefined"

Enumerable_first.call(list); // explicit delegation

console.log("list.first()", list.first()); // "foo"

... mit dem ersten Beispiel auf "instance" Ebene wirkt, und die zweite Abdeckung "class" level ...

var Enumerable_first_last = function () {
  this.first = function () {
    return this[0];
  };
  this.last = function () {
    return this[this.length - 1];
  };
};
console.log("(typeof list.first)", (typeof list.first));  // "function"   // as expected
console.log("(typeof list.last)", (typeof list.last));    // "undefined"  // of course

Enumerable_first_last.call(Array.prototype);  // applying behavior to [Array.prototype]

console.log("list.last()", list.last());      // "baz"  // due to delegation automatism

Wenn man in Not ist für etablierte und / oder Produktion bereit Bibliotheken sollte man auf einen genaueren Blick

  1. traits.js
  2. CocktailJS

so lange

Anhang I

siehe auch:

Anhang II

Da von Zeit zu Zeit bin ich anscheinend Geige mit dieser Angelegenheit ich wan't ein paar letzte Gedanken, um es hinzuzufügen ...

Die Bibliothek agnostischer Ansatz ohne zu viel Kleber-Code (wie oben erwähnt) funktioniert nur für sehr feinkörnig zusammensetzbaren Einheiten von Verhalten Wiederverwendung. Somit kann, wie lange man läuft nicht in mehr als 1 oder 2 leicht auflösbaren Konflikte, Mustern, basierend auf z.B. Angus Croll von Flight Mixins ist der Weg zu folgen.

Wenn es um reale Züge kommt, muss da es sich um eine Abstraktionsebene sein. Diese Schicht (zum Beispiel als eine Art syntaktischen Zuckers wie ein DSL zur Verfügung gestellt) muss die Komplexität zum Beispiel verbergen von Merkmalen aus Züge oder der Konfliktlösung auf einen Züge gelten Zeit (wenn ein Merkmal, das Verhalten auf ein Objekt / Typ angewendet wird).

Komponieren

Mittlerweile gibt es drei Beispiele an, so dass aus meiner Sicht genau das, was die OP fragte ...

  

Wie kann ich Züge in JavaScript implementieren?

Ich empfehle Ihnen, ernsthaft die trait.js Bibliothek zur Kasse. Sie haben auch einen recht guten Artikel über das allgemeine Muster sowie deren konkrete Umsetzung. Ich habe vor kurzem in in mein Projekt gebaut und es funktioniert wie ein Charme.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top