Traços em javascript

Como posso implementar traços em javascript?

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); }; 

Exemplo:

 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] 

Eu realmente recomendo que você faça o checkout da biblioteca trait.js . Eles também têm um bom artigo sobre o padrão geral e sua implementação concreta. Eu recentemente construí no meu projeto e funciona como um encanto.

Existem diferentes abordagens e, ao mesmo tempo, bibliotecas prontas para produção.

Mixins são a forma mais antiga de reutilização de código nas hierarquias de classs. Eles precisam ser compostos em ordem linear, uma vez que o conceito de Mixins não cobre / reconhece a funcionalidade de resolução de conflitos.

Os traços são unidades refinadas de reutilização de código que também funcionam no nível de class; mas eles são mais flexíveis, pois os Traits precisam fornecer aos operadores de composição combinação, exclusão ou aliasing de methods.

Eu recomendo a leitura de 2 artigos que ambos estão cobrindo uma abordagem agnóstica baseada na function pura da biblioteca para Mixins / Traits / Talents.

  1. Um novo olhar para JavaScript Mixins por Angus Croll de maio de 2011
  2. Os muitos talentos do JavaScript para generalizar abordagens de Programação Orientada a Funções, como Traits e Mixins, de abril de 2014.

A function pura e a mecânica de mixin baseada em delegação são tão simples quanto os próximos 2 exemplos …

 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" 

… com o primeiro exemplo atuando no nível “instância” e o segundo cobrindo o nível “class” …

 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 

Se alguém precisa de bibliotecas estabelecidas e / ou prontas para produção, deve-se ter um

  1. traits.js
  2. CocktailJS

tanto tempo

Apêndice I

por favor veja também:

  • stackoverflow.com :: Como usar mixins corretamente em Javascript
  • stackoverflow.com :: Recursos de Padrão de Traços em Javascript

Apêndice II

Desde que, de tempos em tempos, eu aparentemente luto com esse assunto, eu não quero acrescentar alguns pensamentos finais …

A abordagem agnóstica da biblioteca sem muito código de cola (como mencionado acima) funciona apenas para unidades compostas de reutilização comportamental de grão muito fino. Assim, contanto que não haja mais de 1 ou 2 conflitos facilmente resolvidos, padrões baseados, por exemplo, nos Mixins de Voo de Angus Croll são o caminho a seguir.

Se se trata de traços reais, tem que haver um nível de abstração para isso. Esta camada (eg fornecida como algum tipo de açúcar sintático como uma DSL) precisa esconder a complexidade, por exemplo, de compor traços de traços ou de resolução de conflitos em um tempo de aplicação de traços (quando o comportamento de uma característica é aplicado a um object / tipo).

Até agora há 3 exemplos no SO que, na minha perspectiva, fornecem exatamente o que o OP pediu…

Como posso implementar traços em javascript?

  • stackoverflow.com :: Composições e mixins em JS
  • stackoverflow.com :: Mixins para classs ES6, transpilado com babel
  • stackoverflow.com :: Refatorando hierarquias de classs baseadas em mixin legacy
  • stackoverflow.com :: Herança múltipla usando classs