Trong JS, chúng ta chỉ có thể kế thừa từ một object, bên trong mỗi object chỉ chứa duy nhất một property [[Prototype]]
, và một class
thì chỉ extends
từ một class khác.
Đôi khi như vậy khá giới hạn, điều này đẻ ra khái niệm mixins, cho phép một class có thể sử dụng các phương thức của một class khác mà không cần kế thừa
let sayHiMixin = {
sayHi() {
alert(`Hello ${this.name}`);
},
sayBye() {
alert(`Bye ${this.name}`);
}
}
// Sử dụng
class User {
constructor(name) {
this.name = name;
}
}
Object.assign(User.prototype, sayHiMixin)
new User("Andy").sayHi();
Chúng ta không kế thừa, mà đơn giản là merge tất tả các phương thức lại thông qua prototype
Bản thân một mixin cũng có thể kế thừa từ một mixin khác
let sayMixin = {
say(phrase) {
alert(phrase);
}
}
let sayHiMixin = {
// hoặc sử dụng Object.setPrototypeOf
__proto__: sayMixin,
sayHi() {
// gọi đến phương thức từ mixin kế thừa
super.say(`Hello ${this.name}`); },
sayBye() {
super.say(`Bye ${this.name}`); // (*)
}
}
super
sẽ gọi đến phương thức kế thừa từ cha
Ứng dụng mixin vào thực tế, khai báo một EventMixin để tất cả các function/class/object có thể sử dụng truyền đi một thông tin nào đó
trigger
bắn sự kiện và các thông tin đính kèmon
subcribe một handler với một sự kiệnoff
unsubscribe khỏi sự kiện
let eventMixin = {
/**
* subcribe trên sự kiện
* sử dụng menu.on('select', function(item) { ... })
*/
on(eventName, handler) {
if (!this._eventHandlers) this._eventHandlers = {};
if (!this._eventHandlers[eventName]) {
this._eventHandlers[eventName] = [];
}
this._eventHandlers[eventName].push(handler);
},
/**
* unsubcribe
* menu.off('select', handler)
*/
off(eventName, handler) {
let handlers = this._eventHandlers?.[eventName];
if (!handlers) return;
for(let i = 0; i < handlers.length; i++) {
if(handlers[i] === handler) {
handlers.splice(i--, 1)
}
}
},
/**
* Trigger event
* this.trigger('select', data1, data2)
*/
trigger(eventName, ...args) {
if (!this._eventHandlers?.[eventName]) {
return;
}
// gọi handler
this._eventHandlers[eventName].forEach(
handler => handler.apply(this, args)
)
}
}
Sử dụng
class Menu {
choose(value) {
this.trigger("select", value);
}
}
Object.assign(Menu.prototype, eventMixin);
let menu = new Menu();
menu.on("select", value => alert(`Value selected: ${value}`));
menu.choose("123");
Tóm ý
- mixin là một phương pháp trong object-oriented programming để cho phép một class không cần
extends
nhưng vẫn có thể sử dụng các phương thức từ class khác - Các ngôn ngữ khác có thể cho phép đa kế thừa, tuy nhiên điều này không được trong js, phải dùng mixin
- Vấn để của mixin là sẽ ghi đè những phương thức trùng tên
Initializing...