Черты в javascript

Как я могу реализовать черты в javascript?


person Tinku    schedule 30.12.2009    source источник


Ответы (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]
person Thomas Eding    schedule 30.12.2009
comment
TOrd.useBy перемещен за пределы конструктора Rational, чтобы вместо этого воздействовать на прототип. - person Thomas Eding; 31.12.2009
comment
круто круто! Старый добрый язык! Хорошие новые мысли - person asyncwait; 24.02.2011
comment
К сожалению, нет пояснений построчно. - person Thielicious; 18.06.2020

Существуют разные подходы, а также готовые к производству библиотеки.

Миксины — старейшая форма повторного использования кода в иерархии классов. Они должны быть составлены в линейном порядке, так как концепция миксинов не охватывает/не распознает функции разрешения конфликтов.

Черты — это детализированные единицы повторного использования кода, которые также работают на уровне класса; но они более гибкие, поскольку Traits должны предоставлять операторы композиции для комбинирования, исключения или сглаживания методов.

Я рекомендую прочитать 2 статьи, обе из которых охватывают независимый от библиотеки подход, основанный на чистых функциях, для Mixins / Traits / Talents.

  1. Новый взгляд на миксины JavaScript Ангус Кролл, май 2011 г.
  2. Многочисленные таланты 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

Если вам нужны установленные и / или готовые к производству библиотеки, вам следует более внимательно изучить

  1. traits.js
  2. CocktailJS

пока

Приложение I

см. также:

Приложение II

Так как время от времени я видимо возился с этим вопросом, то не хочу добавлять к нему заключительные мысли...

Подход, не зависящий от библиотеки, без слишком большого количества связующего кода (как упоминалось выше) работает только для очень мелких компонуемых единиц поведенческого повторного использования. Таким образом, пока человек не сталкивается с более чем 1 или 2 легко разрешимыми конфликтами, шаблоны, основанные, например, на Flight Mixins Ангуса Кролла — это путь, которому нужно следовать.

Если дело доходит до реальных черт, для этого должен быть уровень абстракции. Этот слой (например, предоставленный как своего рода синтаксический сахар, такой как DSL) должен скрывать сложность, например. составления признаков из признаков или разрешения конфликтов во время применения признаков (когда поведение признака применяется к объекту/типу).

К настоящему времени в SO есть 3 примера, которые, с моей точки зрения, обеспечивают именно то, о чем просил ОП…

Как я могу реализовать черты в javascript?

person Community    schedule 20.05.2014

Я настоятельно рекомендую вам ознакомиться с библиотекой trait.js. У них также есть неплохая статья об общей схеме, а также об их конкретной реализации. Недавно я встроился в свой проект, и он работает как шарм.

person bennidi    schedule 08.07.2014