当 JavaScript
已经成为众人关注的开发语言,JavaScript
已经有了相当大的进步--一个真实意义上的自助开发。但是有一种基于 Mixin
的增强模式在日常开发中很少被使用的。Mixins
经常被一些 JavaScript
所忽略掉(我也经常这么干)。我不想抱怨但是 Mixins
有时候会让代码变得难以读懂。但 Mixins
也有许多优点可以供我们使用的。
Mixin
模式--如名字一样--是一种把一个对象与其他对象混合在一起来增加我们所需要的属性。把它想成一个可以让你的对象新增额外属性但是这些独立的属性却不是真正意义上成为子类挂靠在对象上。
在表面看来,mixins
就像是把目标(mixin
)插入到源对象的混合层。目标会被插入到源对象中并且产生一个新的对象返回。
一个更加准确的描述是--一个 mixin
就像一个新建子类对象并返回的工厂。通过整个过程,不会再有关于子类的任何定义。
用更加 C++
的类比来对比就是在抽象类上的虚拟函数,允许它们去被别的子类进行继承。
所以,现在我们都清楚 mixins
允许我们创建一个可改变的声明,通过这个声明,可以通过存在的父类创建一个新的子类。下面让我们来看下具体实践中 mixin
是怎么工作的:
//The swim property here is the mixin
let swim = {
location() {
console.log(`Heading ${this.direction} at ${this.speed}`);
}
};
let Alligator = function(speed, direction) {
this.speed = speed,
this.direction = direction
};
//This is our source object
let alligator = new Alligator('20 mph','North');
alligator = Object.assign(alligator, swim);
console.log(alligator.location());
在上面的演示中,我想创建一个可以调用 swim
方法的 alligator
实例。所以我先 new
了一个 alligator
实例并且把 swim
对象合上去。swim
对象就是 mixin
或者换种说法是我们想给 alligator
对象通过 Object.assign
方法添加上去的扩展。
Object.assign
方法允许我们每次添加不止一个的 mixin
。一个多 mixin
的例子如下所示:
alligator = Object.assign(alligator, swim, crawl);
现在我们来看下在 ES6 classes
中是怎么使用 mixins
:
let swim = {
setSwimProperties(speed, direction) {
this.speed = speed;
this.direction = direction;
},
getSwimProperties(){
console.log(`swimming ${this.speed} towards ${this.direction}`);
}
}
class Reptile {
constructor(name) {
this.name = name;
}
}
Object.assign(Reptile.prototype, swim);
let alligator = new Reptile("alligator");
alligator.setSwimProperties("5 m/s", "upstream");
alligator.getSwimProperties();
通过 mixin
方法添加功能的优势在于灵活性。mixin
是一个非常原始的方法,因为它只负责一样事情,允许我们在各种情境下重复使用这些结构。它可以用在一个原生的函数调用、一个类的声明等等。
另外一个好处在于它试图让类的结构水平化--通过允许父类去利用这些 mixin
去创建一个指定子类属性的新的对象而不用更长的遗传链去创建子类。
在我们使用 mixins
的时候要牢记下面所提到的东西:
Object.assign
(无论在object
还是class
实现中)只是对于这些mixin
的属性进行浅拷贝。- 在使用从不同
mixin
中的属性时会存在潜在的命名冲突的问题(多重继承中的命名空间问题) - 在这些
mixin
属性被拷贝到源对象之后,我们基本没有办法去区分出这些属性究竟是从哪里来的。instanceof
操作符在这里并没有用武之地。