Подтвердить что ты не робот

Черты в javascript

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

4b9b3361

Ответ 1

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]

Ответ 2

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

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

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

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

Чистая функция и механика смешения на основе делегаций так же проста, как и в следующих двух приведенных примерах...

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

см. также:

Приложение II

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

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

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

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

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

Ответ 3

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