在 JavaScript 中,mixins 允许你将其他对象或类的属性添加到目标对象或类的原型中,并扩展目标对象的功能。之后,你可以使用目标对象访问其他对象的方法。
在 JavaScript 中,每个对象都有一个内置的属性叫做原型。原型本身也是一个对象,所以原型对象也会有自己的原型属性,这就是所谓的原型链。原型链帮助从其他对象继承属性和方法。
同样可以说,mixins 允许你借用其他对象或类的功能。
在 JavaScript 中,继承允许你扩展对象或类的功能。类似地,mixins 也允许你扩展对象或类的功能。
JavaScript 中 Mixins 与对象
利用 JavaScript 的 mixins 概念,可以通过添加其他对象的属性和方法来扩展目标对象的功能。
语法
以下是使用 Mixins 与对象的语法:
Object.assign(target, obj);
在上面的语法中,我们使用 Object.assign()
方法来扩展目标对象的功能。
参数
示例
在下面的代码中,parent
对象包含 printMessage()
方法,而 child
对象包含 showName()
方法。这两个方法分别打印不同的消息。
之后,我们使用 Object.assign()
方法通过 parent
对象的方法扩展 child
对象的功能。
接着,我们仅使用 child
对象调用 parent
和 child
对象的消息,并观察输出结果。
<html>
<body>
<p id="output"> </p>
<script>
const output = document.getElementById("output");
const parent = {
name: "parent",
printMessage() {
output.innerHTML = '这是父对象。<br>';
}
}
const child = {
showName() {
output.innerHTML += '这是子对象。<br>';
}
}
Object.assign(child, parent);
child.printMessage();
child.showName();
</script>
</body>
</html>
输出:
这是父对象。
这是子对象。
JavaScript 中 Mixins 与类
你也可以通过对象使用 mixins 来扩展类的功能。
语法
我们可以按照以下语法使用 mixins 与类:
Object.assign(class_name.prototype, obj);
在上面的语法中,我们将类的原型作为第一个参数,并将需要扩展功能的对象作为第二个参数传递。
示例
在下面的代码中,animal
对象包含 eats
属性和 run()
方法。cat
类只包含构造器。
我们将 animal
对象的方法和属性添加到 cat
类的原型中。之后,我们使用 cat
类的实例执行 run()
方法。
<html>
<body>
<p id="output"> </p>
<script>
const output = document.getElementById("output");
const animal = {
eats: true,
run() {
output.innerHTML += "动物会跑。<br>";
}
}
class Cat {
constructor() {
this.name = "猫";
}
}
Object.assign(Cat.prototype, animal);
const catObj = new Cat();
output.innerHTML += "猫吃东西: " + catObj.eats + "<br>";
catObj.run();
</script>
</body>
</html>
输出:
猫吃东西: true
动物会跑。
利用 Mixins 实现多重继承
JavaScript 不支持多重继承,这意味着不能直接扩展多个类或对象的功能。因此,你可以使用 mixins 来实现多重继承。
语法
用户可以按照以下语法使用 mixins 实现多重继承:
Object.assign(target, ob1, obj);
上述语法会将 obj1
和 obj2
对象的功能添加到目标对象中。
示例:继承多个对象
在下面的代码中,eat
对象包含 eatFood()
方法,而 drink
对象包含 drinkWater()
方法。
我们将 eat
和 drink
对象的属性和方法添加到 person
对象中。之后,我们使用 person
对象访问 eatFood()
和 drinkWater()
方法。
<html>
<body>
<div id="demo"> </div>
<script>
const output = document.getElementById("demo");
const eat = {
eatFood() {
output.innerHTML += "人在吃饭!<br>";
}
}
const drink = {
drinkWater() {
output.innerHTML += "人在喝水!<br>";
}
}
const person = {
name: "John",
}
Object.assign(person, eat, drink);
person.eatFood();
person.drinkWater();
</script>
</body>
</html>
输出:
人在吃饭!
人在喝水!
示例:类的多重继承
下面的例子展示了如何扩展一个类的功能,同时继承多个类。
Entity
类是父类,包含 state()
方法。Human
类继承自 Entity
类,并包含 walk()
方法。
Driver
函数创建一个新的类,扩展一个作为参数传递的类,并向类中添加 Drive()
方法。同样地,Swimmer
函数创建一个新的类,扩展一个作为参数传递的类,并向类中添加 swim()
方法。
之后,我们定义了多个其他类。Person
类扩展了 Driver
类返回的类。Driver
函数返回一个扩展自 Human
类的新类。同理,我们创建了 Mechanic
和 SwimmerPerson
类。
之后,我们创建了各种类的实例,并执行它们继承的方法。
<html>
<body>
<p id="demo"> </p>
<script>
let output = document.getElementById("demo");
class Entity {
state() {
return '它处于空闲状态!';
}
}
class Human extends Entity {
walk() {
return '正在田野里行走。';
}
}
function Driver(parentClass) {
return class extends parentClass {
drive() {
return '在路上开车';
}
};
}
function Swimmer(parentClass) {
return class extends parentClass {
swim() {
return '在水里游泳';
}
};
}
class Person extends Driver(Human) { }
class Mechanic extends Driver(Entity) { }
class SwimmerPerson extends Swimmer(Person) { }
const person = new Person();
const personDrive = person.drive();
const mechanic = new Mechanic();
const mechanicDrive = mechanic.drive();
const swimmerPerson = new SwimmerPerson();
const swimmerDrive = swimmerPerson.drive();
const swimmerSwim = swimmerPerson.swim();
output.innerHTML += '人的状态: ' + personDrive + '<br>';
output.innerHTML += '机械师的状态: ' + mechanicDrive + '<br>';
output.innerHTML += '游泳者人的状态: ' + swimmerDrive + ", " + swimmerSwim + '<br>';
</script>
</body>
</html>
输出:
人的状态: 在路上开车
机械师的状态: 在路上开车
游泳者人的状态: 在路上开车, 在水里游泳
这种方式,你可以使用 mixins 来实现多重继承。
Mixins 的优点
-
代码复用 - 你可以通过借用其他对象或类的方法和属性来重用代码。
-
多重继承 - JavaScript 默认不支持多重继承,但你可以使用 mixins 达到类似的功能。
-
扩展性 - 使用 mixins,你可以在不改变对象或类结构的情况下为其添加额外的功能。
Mixins 的局限性
-
复杂度 - 如果过度使用 mixins,会导致代码复杂度增加,这在本教程的最后一个示例中可以看到。
-
伪继承 - mixins 可以满足继承的需求,但使用 mixins 无法达到真正的继承。
-
命名冲突 - 如果组合多个对象,很可能出现命名冲突。