一、许多OO语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。在ECMAScript中,由于函数没有签名,所以无法实现接口继承,即只能支持实现继承。
js中的继承模式有以下几种:原型链、借用构造函数、组合继承、原型式继承、寄生式继承、寄生组合式继承,而其实现继承主要是依靠原型链来实现的。
二、以上几种继承模式的优缺点以及相关性
1,原型链继承的基本思想,是利用原型让一个引用类型继承另一个引用类型的属性和方法。实现的本质就是重写原型对象,即让原型对象等于另一个类型的实例。
注意:在通过原型链实现继承时,不能使用对象字面量创建原型方法,因为这样做会重写原型链。
原型链虽然很强大,可以实现继承,但它也存在一些问题:
1>最主要的问题来自于包含引用类型值的原型,包含引用类型值的原型属性会被所有实例共享。在通过原型实现继承时,原型实际上变成另一个类型的实例,于是,另一个类型的实例属性也就变成了现在的原型属性了。对于实例化的新对象1,新对象2,假如新对象1在改变继承的引用类型值(比如数组)属性时,会直接反映到该对象的原型中,进而新对象2中相对应的引用类型值也“被动”地跟着变化(详解可以参考JS高级程序设计第166页的讲解)。
2>创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。
综上,实践中很少会单独使用原型链。
2, 借用构造函数解决了原型链中存在的以上问题,这种技术的基本思想,即在子类型构造函数的内部调用超类型构造函数(使用apply()和call()方法)。
但是仅仅使用借用构造函数,将无法避免构造函数模式存在的问题——方法都在构造函数中定义,因此函数复用就无从谈起了。
综上,借用构造函数的技术也是很少单独使用的。
3,组合继承(伪经典继承),指的是将原型链和借用构造函数的技术组合在一起,从而发挥二者之长的一种继承模式。背后思路是:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
组合继承是JS最常用的继承模式,不过他也有不足之处,即它最大的问题就是无论什么情况下,都会调用两次超类型构造函数。一次是在创建子类型原型的时候,另一次是在子类型构造函数内部(可以参考JS高级程序设计第三版第172页的讲解)。
4,寄生组合式继承解决了组合继承的上述问题,所谓寄生组合式继承,指通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。他的高效性体现在它只调用一次超类型构造函数,开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
以下是原型式继承和寄生式继承,两者思路紧密相关。
5,原型式继承的思想是,借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
6,寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,然后函数在内部以某种方式来增强对象,最后再像真地是他做了所有工作一样返回对象。
注:方法签名由方法的名称和它的每一个形参(按从左到右的顺序)的类型和种类(值、引用或输出)组成。需注意的是,方法签名既不包含返回类型,也不包含 params 修饰符(它可用于最右边的参数)。