JavaScript继承详解(Mixin)

27 Jul

上一篇JavaScript继承详解(Klass)介绍了各种继承的模式。但究竟为何要继承?一个很重要的目的就是为了代码复用。因此还有一种非常简单粗暴的方式,直接无脑拷贝父对象的各属性。

另一种继承模式:通过复制属性实现继承。将对象从另一个对象中获得需要复制功能:

function extend(parent, child) {
    var i;
    child = child || {};
    for(i in parent) {
        if(parent.hasOwnProperty(i)) {
            child[i] = parent[i];
        }
    }
    return child;
}
var p1 = {name:"Jack"};
var c1 = extend(p1);
console.log(c1.name);	//Jack

上面是浅复制,遍历父对象的属性复制给子对象,但如果属性是数组或对象,只会浅复制属性:

var p2 = {
    counts: [1, 2, 3],
    interest: {read: true}
};
var c2 = extend(p2);
console.log(p2.interest === c2.interest);	//true

c2.counts.push(4);
console.log(p2.counts.toString());	//1,2,3,4
c2.interest.play = true;
console.log(p2.interest.play);		//true

JS里浅复制的概念和传统OO语言里对指针的浅复制一样,并无二致。上例中在子类对象上,对数字或对象属性进行操作会影响到父类对象。通常这不是我们想要的效果,因此要改成深复制,即如果属性是数组或对象就深复制该属性:

function extend(parent, child) {
    var i;
    child = child || {};
    for(i in parent) {
        if(parent.hasOwnProperty(i)) {
	    if(typeof parent[i] === "object") {
                child[i] = (Array.isArray(parent[i])) ? [] : {};
                extend(parent[i], child[i]);
            } else {
                child[i] = parent[i];
            }
        }
    }
    return child;
}

var p3 = {
    counts: [1, 2, 3],
    interest: {read: true}
};
var c3 = extend(p3);
console.log(p3.interest === c3.interest);	//false

c3.counts.push(4);
console.log(c3.counts.toString());	//1,2,3,4
console.log(p3.counts.toString());	//1,2,3
c3.interest.play = true;
console.log(c3.interest.play);	//true
console.log(p3.interest.play);	//undefined

这种模式被广泛使用,Firebug的extend方法是浅复制,jQuery的extend是深复制。当然不论是浅复制还是深复制,并没有涉及原型,仅复制它们自身的属性。

Mix-in

这种复制属性实现继承的思想可以进一步扩展成Mix-in混入模式。并不完整地复制一个对象,而是从多个对象中复制出属性,将其组合成一个新对象

function mixin() {
    var i, prop, child = {};
    for(i=0; i<arguments.length; i+=1) {
        for(prop in arguments[i]) {
            if(arguments[i].hasOwnProperty(prop)) {
                child[prop] = arguments[i][prop];
            }
        }
    }
    return child;
}

你可以用它传递任意数量的对象:

var person = mixin(
    {age:33, gender:'male', location:'Shanghai'},
    {interest: "read travel"},
    {job: "IT"}
);
console.dir(person);
//arg  	    33
//gender    "male"
//interest  "read travel"
//job	    "IT"
//location  "Shanghai"

总结

本文结合JavaScript继承详解(Klass)把继承介绍的差不多了。你能在各种库中找到各种模式的蛛丝马迹。当然有时候简单的代码复用其实没必要用继承,你只不过想借用别人的方法,并不希望与它们形成父子关系,那你用call和apply即可。

Leave a Reply

Your email address will not be published. Required fields are marked *