mixin 是一个对象,我们可以使用它向另一个对象或类添加可重用的功能,而无需使用继承。我们不能单独使用 mixin:它们的唯一目的是在没有继承的情况下向对象或类添加功能。
假设我们的应用程序需要创建多只狗。然而,我们创建的基本狗除了 name
属性之外没有任何属性。
class Dog {
constructor(name) {
this.name = name;
}
}
狗应该能够做的不仅仅是有名字。它应该能够吠叫、摇尾巴和玩耍!我们可以创建一个 mixin 来为我们提供 bark
、 wagTail
和 play
属性,而不是直接将其添加到 Dog
中。
const dogFunctionality = {
bark: () => console.log("Woof!"),
wagTail: () => console.log("Wagging my tail!"),
play: () => console.log("Playing!"),
};
我们可以使用 Object.assign
方法将 dogFunctionality
mixin 添加到 Dog
原型中。此方法允许我们向目标对象添加属性:在本例中为 Dog.prototype
。 Dog
的每个新实例都可以访问 dogFunctionality
的属性,因为它们被添加到 Dog
的原型中。
class Dog {
constructor(name) {
this.name = name;
}
}
const dogFunctionality = {
bark: () => console.log("Woof!"),
wagTail: () => console.log("Wagging my tail!"),
play: () => console.log("Playing!"),
};
Object.assign(Dog.prototype, dogFunctionality);
让我们创建我们的第一个宠物 pet1
,名为 Daisy。由于我们刚刚将 dogFunctionality
mixin 添加到 Dog
的原型中,Daisy 应该能够走路、摇尾巴和玩耍!
const pet1 = new Dog("Daisy");
pet1.name; // Daisy
pet1.bark(); // Woof!
pet1.play(); // Playing!
Mixins 使我们可以轻松地向类或对象添加自定义功能,而无需使用继承。
虽然我们可以使用 mixins 添加功能而无需继承,但 mixins 本身可以使用继承。大多数哺乳动物(除了海豚……也许还有更多)也可以行走和睡眠。狗是哺乳动物,应该能够行走和睡觉。
让我们创建一个添加 walk
和 sleep
属性的 animalFunctionality
mixin。
const animalFunctionality = {
walk: () => console.log("Walking!"),
sleep: () => console.log("Sleeping!"),
};
我们可以使用 Object.assign
将这些属性添加到 dogFunctionality
原型中。在本例中,目标对象是 dogFunctionality
。
const animalFunctionality = {
walk: () => console.log("Walking!"),
sleep: () => console.log("Sleeping!"),
};
const dogFunctionality = {
bark: () => console.log("Woof!"),
wagTail: () => console.log("Wagging my tail!"),
play: () => console.log("Playing!"),
walk() {
super.walk();
},
sleep() {
super.sleep();
},
};
Object.assign(dogFunctionality, animalFunctionality);
Object.assign(Dog.prototype, dogFunctionality);
现在Dog
的任何新实例现在也可以访问 walk
和 sleep
方法。
const pet1 = new Dog("Daisy");
console.log(pet1.name);
pet1.bark();
pet1.play();
pet1.walk();
pet1.sleep();
现实世界中 mixin 的示例在浏览器环境中的 Window
界面上可见。 Window
对象实现了许多如 WindowOrWorkerGlobalScope
和 WindowEventHandlers
的 mixin 属性,这使得我们能够访问 setTimeout
等属性和 setInterval
、 indexedDB
和 isSecureContext
。
由于它是一个 mixin,因此仅用于向对象添加功能,因此您将无法创建 WindowOrWorkerGlobalScope
类型的对象。
window.indexedDB.open("toDoList");
window.addEventListener("beforeunload", (event) => {
event.preventDefault();
event.returnValue = "";
});
window.onbeforeunload = function () {
console.log("Unloading!");
};
console.log(
"From WindowEventHandlers mixin: onbeforeunload",
window.onbeforeunload
);
console.log(
"From WindowOrWorkerGlobalScope mixin: isSecureContext",
window.isSecureContext
);
console.log(
"WindowEventHandlers itself is undefined",
window.WindowEventHandlers
);
console.log(
"WindowOrWorkerGlobalScope itself is undefined",
window.WindowOrWorkerGlobalScope
);
React (pre ES6)
在引入 ES6 类之前,Mixin 通常用于向 React 组件添加功能。 React 团队不鼓励使用 mixins,因为它很容易给组件增加不必要的复杂性,使其难以维护和重用。 React 团队鼓励使用更高阶的组件,现在这些组件通常可以被 Hook 取代。
Mixins 允许我们通过将功能注入到对象的原型中,轻松地向对象添加功能,而无需继承。修改对象的原型被认为是不好的做法,因为它可能导致原型污染以及函数起源的一定程度的不确定性。