盗用构造函数 又叫做 对象伪装 或 经典继承,是一种不涉及原型对象的继承方式。
一 方案优势
解决了原型包含引用值导致的继承问题。
当原型包含引用值的时候,该引用值会在所有实例间共享。如下,在obj中改变的引用值在obj2中共享了。
function objA(){
this.title = 'A';
this.numArr = ["One", "Two", "Three"];
}
function objB(){
this.title = 'B';
}
objB.prototype = new objA();
var obj = new objB;
obj.numArr.push("Four");
console.log(obj.numArr.valueOf()); // ["One", "Two", "Three", "Four"]
var obj2 = new objB;
console.log(obj2.numArr.valueOf()); // ["One", "Two", "Three", "Four"]
要解决此问题,就不能把继承中非共享的引用值放置到原型对象中,我们可以在子类构造函数中调用父类构造函数,将父类构造函数的属性挂载到子类中。
这样在构建子类实例时,非共享的引用值就会和实例的其他普通属性放在一起,而不是放在原型对象中。
二 代码实现
下面的代码中,需要一个继承了objA与objB属性的实例,但是没有单独调用objA,而是将objA的调用嵌入到objB中,这样在使用构造函数构造B的实例时,也会继承A的构造属性。
从输出中也可看出,A与B的属性都直接写入了B的实例中。
function objA(){
this.title = 'A';
this.numArr = ["One", "Two", "Three"];
}
function objB(){
this.title = 'B';
objA.call(this);
}
var obj = new objB;
console.log(obj);
// obj = {
// numArr: ["One", "Two", "Three"],
// title: "A"
// }
obj.numArr.push("Four");
var obj2 = new objB;
console.log(obj2);
// obj2 = {
// numArr: ["One", "Two", "Three"],
// title: "A"
// }
三 方案缺陷
无可共享的属性,方法需要在构造函数中定义,无法有效重用。
如果你看过前面的JavaScript: 原型链继承(原理解析 + 代码实现 + 结构图解)这章,就容易想到,一个是过度重用,一个是无法共享,如果两者结合使用,取两者的优势,就完美了。
这就是另一种继承方式:组合继承。
其他的继承方法请关注本专栏,等待后续文章。