Przykład pochodzi z pewnego projektu dostępnego na GitHubie i szczerze powiedziawszy, nigdy i nigdzie nie znalazłem lepszego patentu na mixiny w JS. Możemy osiągnąć multi-dziedziczenie w bardzo prosty sposób.
Zacznijmy od tego, że klasa może dziedziczyć nie tylko inną klasę, ale także funkcję. Wygląda to mniej więcej tak:
const fn = function() {
//(...)
};
class Something extends fn {
//(...)
}
Mamy też funkcję Object.assign, która przyjmuje (i zwraca) target oraz źródło/źródła. Możemy zatem zrobić to tak:
export function mixin(...mixins) {
const fn = function() {};
Object.assign(fn.prototype, ...mixins);
return fn;
}
Targetem jest prototyp fn, zaś źródłami mixiny. Zwracamy fn, choć prawdopodobnie zwrócenie Object.assign też by zadziałało, jeżeli wierzyć dokumentacji MDN:
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// Expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget === target);
// Expected output: true
Tak czy inaczej, możemy teraz używać mixinów:
class eQuery extends mixin(Attributes, Iteration, Content, Events) {
constructor(nodes) {
super();
if( !Array.isArray(nodes) ) {
nodes = [nodes];
}
_NODES.set(this, nodes);
}
}
Musimy tylko pamiętać o super w konstruktorze. I o imporcie.
A jak taki mixin wygląda?
export default {
on(type, fn) {
return this.each( node => node.addEventListener(type, fn, false) );
},
off(type, fn) {
return this.each( node => node.removeEventListener(type, fn, false) );
}
};
To obiekt zawierający funkcje. Rozwiązanie z tego projektu jest genialne w swojej prostocie a zarazem jest to chyba najlepszy patent na mixiny, jaki widziałem.