Как я могу реализовать черты в javascript?
Черты в javascript
Ответы (3)
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);
};
Пример:
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]
Существуют разные подходы, а также готовые к производству библиотеки.
Миксины — старейшая форма повторного использования кода в иерархии классов. Они должны быть составлены в линейном порядке, так как концепция миксинов не охватывает/не распознает функции разрешения конфликтов.
Черты — это детализированные единицы повторного использования кода, которые также работают на уровне класса; но они более гибкие, поскольку Traits должны предоставлять операторы композиции для комбинирования, исключения или сглаживания методов.
Я рекомендую прочитать 2 статьи, обе из которых охватывают независимый от библиотеки подход, основанный на чистых функциях, для Mixins / Traits / Talents.
- Новый взгляд на миксины JavaScript Ангус Кролл, май 2011 г.
- Многочисленные таланты JavaScript для обобщения подходов ролевого программирования, таких как Traits и Mixins от апреля 2014 года.
Чистая механика примесей, основанная на функциях и делегировании, так же проста, как и в следующих двух приведенных примерах...
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"
... с первым примером, действующим на уровне "экземпляра", а вторым - на уровне "класса"...
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
Если вам нужны установленные и / или готовые к производству библиотеки, вам следует более внимательно изучить
пока
Приложение I
см. также:
- stackoverflow.com :: Как правильно использовать миксины в Javascript
- stackoverflow.com :: Ресурсы шаблонов признаков JavaScript
Приложение II
Так как время от времени я видимо возился с этим вопросом, то не хочу добавлять к нему заключительные мысли...
Подход, не зависящий от библиотеки, без слишком большого количества связующего кода (как упоминалось выше) работает только для очень мелких компонуемых единиц поведенческого повторного использования. Таким образом, пока человек не сталкивается с более чем 1 или 2 легко разрешимыми конфликтами, шаблоны, основанные, например, на Flight Mixins Ангуса Кролла — это путь, которому нужно следовать.
Если дело доходит до реальных черт, для этого должен быть уровень абстракции. Этот слой (например, предоставленный как своего рода синтаксический сахар, такой как DSL) должен скрывать сложность, например. составления признаков из признаков или разрешения конфликтов во время применения признаков (когда поведение признака применяется к объекту/типу).
К настоящему времени в SO есть 3 примера, которые, с моей точки зрения, обеспечивают именно то, о чем просил ОП…
Как я могу реализовать черты в javascript?
- stackoverflow.com :: Композиции и примеси в JS
- stackoverflow.com :: Миксины для классов ES6, перенесенные с помощью babel< /а>
- stackoverflow.com :: Рефакторинг устаревших иерархий классов на основе примесей
- stackoverflow.com :: Множественное наследование с использованием классов
Я настоятельно рекомендую вам ознакомиться с библиотекой trait.js. У них также есть неплохая статья об общей схеме, а также об их конкретной реализации. Недавно я встроился в свой проект, и он работает как шарм.