Mais uma vez vi uma dúvida, do mesmo usuário, no Stack Overflow em Português, com a seguinte pergunta:
O que são “mixins” [em JavaScript]?
Vejo em alguns códigos JavaScript e gostaria de saber o que é; exemplos reais de uso.
Por ter achado interessantíssima a pergunta e algo realmente relevante, decidi então elaborar uma resposta. Pois bem, aos interessados, ela segue abaixo.
Mixin em JavaScript é um uma classe pensada com foco no DRY. Ela dá a habilidade do desenvolvedor pegar atalhos para resolver problemas, quase como os famosos “helpers”, com a diferença de que um mixin pode ou não referenciar ou ser referenciado por um módulo1 sem a necessidade direta de extensão ou herança.
Um exemplo prático e útil
Botões (<button>) e âncoras (<a>) são conceitualmente componentes do DOM, o que significa que quando/se falarmos de “componentes”, estamos indo na síntese do negócio; indo na camada mais genérica dos elementos que a nossa linguagem favorita de marcação trabalha.
Num todo, componentes são materiais renderizáveis; são itens que quando marcados no seu HTML têm a capacidade de se invocar para a visualização do usuário e materialização da interface.
Portanto, exemplifiquei mixin nesse cenário, através de JavaScript. Usando botões e âncoras ainda, desenvolvi os seguintes objetos:
var Button = {
design: {
colors: {
background: 'blue',
text: 'yellow'
},
borderRadius: 3,
padding: 5,
},
shape: function () {
return '<button style="background-color:' + this.design.colors.background + ';'
+ 'border-radius:' + this.design.borderRadius + 'px;'
+ 'padding:' + this.design.padding + 'px;'
+ 'color:' + this.design.colors.text + ';'
+ 'border: none;">'
+ this.getContent()
+ '</button>';
}
};
e
var Anchor = {
design: {
color: 'green',
underline: true
},
destination: 'google.com',
shape: function () {
return '<a style="color:' + this.design.color + ';'
+ 'text-decoration:' + (this.design.underline ? 'underline' : 'none') + ';" '
+ 'href="http://' + this.destination + '">'
+ this.getContent()
+ '</a>';
}
};
Eles possuem características em comum, certo? São exemplos design e shape. Entretanto, se você prestar atenção, são diferenciados pela sua implementação; pela suas características particulares. Em outras palavras, cada um desses “componentes” possui a sua própria personalidade, como a marcação em si, que no caso do botão é <button> e no caso da âncora é <a>.
Relembrando…
Lembra que há pouco falei sobre “renderização”? Pois é, componentes como esses devem ter a capacidade de se manifestarem no DOM. Então, faríamos para ensinar os dois objetos (Button e Anchor) a se projetarem sem cair na repetição de criar métodos iguais em seus escopos? Mixins!
Veja este terceiro objeto que desenhei:
var Component = {
render: function (platform) {
$(platform).html(this.shape());
},
append: function (platform) {
$(platform).append(this.shape());
},
setContent: function (content) {
this.content = content;
return this;
},
getContent: function () {
return this.content;
}
};
Ele, por sua vez, possui recursos que podem tornar os nossos botões e âncoras úteis – e podemos usar livremente clonando o seu escopo entre os nossos dois objetos.
Para a clonagem, por sua vez, utilizei o método extend() do Underscore.js:
_.extend(Anchor, Component); _.extend(Button, Component);
O resultado ficou simples. Para renderizarmos os nossos componentes, faríamos então o seguinte:
Button
.setContent('Register')
.append('body');
Anchor
.setContent('And here if you already have an account!')
.append('body');
Se juntarmos tudo, o resultado será este:
var Component = {
render: function (platform) {
$(platform).html(this.shape());
},
append: function (platform) {
$(platform).append(this.shape());
},
setContent: function (content) {
this.content = content;
return this;
},
getContent: function () {
return this.content;
}
};
var Button = {
design: {
colors: {
background: 'blue',
text: 'yellow'
},
borderRadius: 3,
padding: 5,
},
shape: function () {
return '<button style="background-color:' + this.design.colors.background + ';'
+ 'border-radius:' + this.design.borderRadius + 'px;'
+ 'padding:' + this.design.padding + 'px;'
+ 'color:' + this.design.colors.text + ';'
+ 'border: none;">'
+ this.getContent()
+ '</button>';
}
};
var Anchor = {
design: {
color: 'green',
underline: true
},
destination: 'google.com',
shape: function () {
return '<a style="color:' + this.design.color + ';'
+ 'text-decoration:' + (this.design.underline ? 'underline' : 'none') + ';" '
+ 'href="http://' + this.destination + '">'
+ this.getContent()
+ '</a>';
}
};
_.extend(Anchor, Component);
_.extend(Button, Component);
Button
.setContent('Register')
.append('body');
Anchor
.setContent('And here if you already have an account!')
.append('body');
Para brincar e praticar, aqui está o jsFiddle.



