继承里面的坑

在练习写组件的时候发现了一个有关继承的坑,准确的来说也是我的理解不透彻,没把组合继承和寄生式组合继承的真正区别弄明白,因而在此记录一下。

组合继承

在《Javascript高级程序设计》一书中组合继承表述的是这样的意思:

	//父
    function SuperType(name) {
        this.name = name;
        this.color = ["red", "blue", "green"];
    }

    SuperType.prototype.sayName = function () {
        alert(this.name);
    };

	//子
    function SubType(name, age) {
        SuperType.call(this, name);	//标记为(1)
        this.age = age;
    }

    SubType.prototype = new SuperType();	//标记为(2)
    SubType.prototype.constructor = SubType;
    SubType.prototype.sayAge = function () {
        alert(this.age);
    }

这种方法主要就是两步,也就是我在上面程序中的标记(1)(2)(1)的作用是让子函数继承了父构造函数的属性,(2)的作用是将父构造函数实例化传给了子构造函数的原型。

所以会有

var t1 = new SubType();
console.log(t1.color);	//["red", "blue", "green"]
console.log(t1.hasOwnProperty("name"))	//true
console.log(t1.hasOwnProperty("color"))	//true
console.log(t1.hasOwnProperty("age"))	//true

而去掉(1),其实也继承成功了,只是父构造函数里面的属性全部继承到了子构造函数的原型中,而不是像上面一样也继承到了属性中,如:

//去掉了(1)
var t1 = new SubType("zzr", "23");
console.log(t1.color);	//["red", "blue", "green"]
console.log(t1.hasOwnProperty("name"))	//false
console.log(t1.hasOwnProperty("color"))	//false
console.log(t1.hasOwnProperty("age"))	//true

现在回到没去掉(1)的时候

console.log(SuperType.prototype)
console.log(SubType.prototype)

在chome浏览器下出现下面的结果:

结果很正常,为什么我要拿出来说明呢,其实是为了和接下来要说的对比。

寄生式组合继承

寄生式组合继承与组合继承有一点不同,那就是寄生式组合继承把组合继承中的(2)换成了如下的程序。

//(2)变成了如下
inheritPrototype(SubType, SuperType)

//其中inheritPrototype函数为
function inheritPrototype(subType, superType) {
	var prototype = Object(superType.prototype);
	prototype.constructor = subType;
	subType.prototype = prototype;
}

这样继承的好处是,父构造函数的属性不会再子构造函数里面在继承一遍了。

同样进行如下的测试:

console.log(SuperType.prototype)
console.log(SubType.prototype)

在chome浏览器下出现下面的结果:

在这样继承后,发现父构造函数和子构造函数的原型共用了。所以无论更改哪一个,另一个也同样变化。

总结

在《Javascript高级程序设计》书中关于寄生式组合继承的评价有这么一句话:“开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式”。我当初也是看到了这句话,但却看的不仔细,单纯的理解成了寄生式组合继承就是最好的继承,所以凡是继承就应该用这个,结果在练习组件编写的时候让所有的组件都共用了同一个原型,全部乱套了。现在一看,书上明明说的是引用类型最理想的继承,还是自己当初没理解好。

如果这篇文章对你很有帮助,你可以犒劳一下WO

打赏