Примесь (mixin) — это объект с набором функций, который сам по себе (отдельно от других объектов) не используется.
Вот, например, прекрасная примесь:
var Mixin_Babbler =
{
say: function ()
{
console.log("My name is " + this.name + " and i think:'" + this.THOUGHTS + "'");
},
argue: function() { console.log("You're totally wrong"); }
};При попытке вызвать метод say просто так, нас ждет облом, потому что ни this.name, ни this.THOUGHTS в нашем объекте, почему-то, просто нет.
На самом деле все правильно, чтобы использовать примесь по назначению нам нужен другой объект, и метод, который копирует все свойства переданных ему объектов-примесей в прототип функции конструктора — обычно такой метод называют extend, или mix, или как-нибудь в этом духе:
function extend(object)
{
var mixins = Array.prototype.slice.call(arguments, 1);
for (var i = 0; i < mixins.length; ++i)
{
for (var prop in mixins[i])
{
if (typeof object.prototype[prop] === "undefined")
{
object.prototype[prop] = mixins[i][prop];
}
}
}
}Ну и как это использовать?
Легко и не напрягаясь — допустим, у нас есть парочка примесей:
var Mixin_Babbler =
{
say: function () { console.log("My name is " + this.name + " and i think:'" + this.THOUGHTS + "'"); },
argue: function() { console.log("You're totally wrong"); }
};
var Mixin_BeverageLover =
{
drink: function () { console.log("* drinking " + this.FAVORITE_BEVERAGE + " *"); }
};И, кому-то, возможно, уже знакомая, эволюционная цепочка:
function Man(name)
{
this.name = name;
}
Man.prototype =
{
constructor: Man,
THOUGHTS: "I like soccer"
}
extend(Man, Mixin_Babbler);
function Gentleman(name)
{
this.name = name;
}
Gentleman.prototype =
{
constructor: Gentleman,
THOUGHTS: "I like Earl Grey",
FAVORITE_BEVERAGE: "Tea"
}
extend(Gentleman, Mixin_Babbler, Mixin_BeverageLover);
function Programmer(name)
{
this.name = name;
}
Programmer.prototype =
{
constructor: Programmer,
THOUGHTS: "MVC, MVVM, MVP *___* like it!",
FAVORITE_BEVERAGE: "Cofee",
write_good_code: function () { console.log("*writing best code ever*"); this.drink(); }
}
extend(Programmer, Mixin_Babbler, Mixin_BeverageLover);Каждый «класс» теперь не зависит от другого, а весь повторяющийся функционал реализован с помощью примесей.
Теперь стоит все проверить — вдруг заработает:
var man = new Man("Bob");
var gentleman = new Gentleman("Bill");
var programmer = new Programmer("Benjamin");
man.say();
man.argue();
gentleman.say();
gentleman.drink();
programmer.say();
programmer.write_good_code();И консоль говорит что таки да, все как надо:
My name is Bob and i think:'I like soccer' *You're totally wrong* My name is Bill and i think:'I like Earl Grey' *drinking Tea* My name is Benjamin and i think:'MVC, MVVM, MVP like *__* it!' *writing best code ever* *drinking Cofee*
Собственно все. В отличие от «классического» наследования, реализация примесей очень простая и понятная. Существуют конечно некоторые вариации, но так или иначе ядро выглядит именно так.


