JS 继承:extend、mixin 和 plugin(二)
Mixin:
Mixin 是一种JS实现多继承方式,它通过复制其他类原型链(prototype)上的方法到自身原型链(prototype)上,来实现多继承。根据定义我们可以实现函数:
/**
* 将其他类作为mixin集成到指定类上面
* @param {Function} c 构造函数
* @param {Array} mixins 扩展类
* @return {Function} 传入的构造函数
*/
function mixin(c,mixins){
var prototype = c.prototype;
$.each(mixins, function (index,ext) {
if (ext) {
var proto = ext.prototype;
for (var p in proto) {
prototype[p] = proto[p];
}
}
});
return c;
}
有了这个方法,我们来做一下实验:
function A(){};
A.prototype = {
method:function(){
return 'a';
},
methodA:function(){
}
};
function B(){};
B.prototype = {
method:function(){
return 'b';
},
methodB:function(){
}
};
function C(){}
C.prototype = {
method:function(){
return 'c';
},
methodC:function(){
}
};
mixin(C,[A,B]);
var c = new C();
alert(c.method()); //输出 b
此时我们看到结果是’b’但是根据继承的定义,子类的方法覆盖父类,所以这个结果不是我们想要的。我们需要子类的方法覆盖minxins 的方法。那么我们继续更改:
function mixin(c,mixins){
var prototype = {},
constructors = mixins['concat'](c);
$.each(constructors , function (index,ext) {
if (ext) {
var proto = ext.prototype;
for (var p in proto) {
prototype[p] = proto[p];
}
}
});$.each(prototype, function (k,v) {
c.prototype[k] = v;
});
return c;
}
此时再执行上面的结果,
var c = new C();
alert(c.method()); //输出 c
看上去现在mixin我们完整的实现了,但是如果C本来继承了Base类,而Base类又有方法跟mixins中的类的方法重复,我们怎么办:
function Base(){}
Base.prototype = {
method:function(){
return 'base';
},
methodA:function(){
return 'base';
}
};
function C(){
}
extend(C,Base);
C.prototype.method = function(){
return ‘c’
}
mixin(C,[A,B]);
var c = new C();
alert(c.method()); //输出 c
alert(c.methodA()); //输出 base
但是从继承的概念上讲,Base没有继承mixins中的方法,所以C从minxins中继承来的方法的优先级应该高于Base类中的方法,所以我们需要覆盖父类的方法,那么我们minxin 的最终版本是:
function mixin(c,mixins){
var prototype = {},
constructors = mixins['concat'](c);
$.each(constructors , function (index,ext) {
if (ext) {
var proto = ext.prototype;
for (var p in proto) {
//由于本身的构造函数在最后面,父类的方法不覆盖mixins中的方法
if (proto.hasOwnProperty(p)) {
prototype[p] = proto[p];
}
}
}
});
$.each(prototype, function (k,v) {
c.prototype[k] = v;
});
return c;
}
小结:
Mixin 在实现JS的继承是一种非常强大的方式,特别是写控件时,可以将大量抽象的逻辑封装成一个个的mixin,我们在实现一个控件时,可以将这些mixins直接引入控件类上,不需要重新编写实现。后面我会讲解一些常见的mixin。
下一节我会讲解plugin ,同时对比plugin 跟 mixin的实现场景。