上一篇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即可。