继承包括:
- 接口继承
- 实现继承
1.原型链
基本思想:利用原型让一个引用类型继承另一个引用类型的属性和方法。
假如我们让原型对象等于另一个类型的实例,会这样呢?
这时当前原型就是另一个类型的实例,并且它还有一个指针指向了另一个原型对象,另一个原型对象也会有一个指针指向了另一个构造函数。假如另一个原型又是另一个类型的实例,那么上述的关系依然成立,层层递进,就构成了实例和原型的链条。这就是所谓原型链的基本概念。
实现原型链有一种基本模式:
重点代码:
SubType.prototype = new SuperType()
原型链的问题是:
- 最主要的问题来自于包含引用类型值的原型。
- 第二个问题是在创建子类型的实例时,不能向超类型的构造函数传递参数。
于是就有了借用构造函数的诞生:
2.借用构造函数
基本思想:在子类型的构造函数调用超类型的构造函数。
function SubType(){
//继承
SuperType.call(this);
}
借用构造函数的问题:
- 方法都是在构造函数中定义的,因此无法复用。
- 在超类型的原型中定义的原型方法对于子类型中都是不可见的,结果所有类型都只能使用构造函数模式。
3.组合继承
组合继承也叫做伪经典继承,指的是将原型链和借用构造函数的技术整合在一起,发挥它们的长处。
其思想是:使用原型链实现对原型属性和方法的继承,而通过借用构造函数实现对实例属性的继承。
function SubType(){
SuperType.call(this);
}
SubType.prototype = new SuperType();
组合继承避免了原型链和借用构造函数的缺点,融合了它们的有点,因此也是JavaScript最常用的继承模式。
4.原型继承
道格拉斯在一遍文章上介绍了一种实现继承的方法,这种方法并没有严格意义上的构造函数。
他的想法是:借助原型在已有对象上创建新的对象,同时还不必因此创建自定义类型。
function obect(o){
function F(){}
F.prototype = o;
return new F()
}
在没有必要兴师动众地创建构造函数,而只想让一个对象和另一个对象保持类似的情况下,原型式继承是完全可以胜任的。
不过别别忘了,包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。
5.寄生式继承
思路:与寄生构造函数模式和工厂模式类似,即创建一个用于封装继承过程的函数,该函数在内部以某种方式增强,最后再像是真地是它做了所有工作一样返回对象。
function createAnother(original){
var clone = object(original);
clone.sayHi = funciton(){
console.log('Hi);
}
return clone;
}
在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式也是一种有用的模式。
6.寄生组合式继承
前面说过组合继承是JavaScript最常用的继承,但它也是有问题的,问题在于调用了两次超类型的构造函数,
- 一次在子类型的原型上
- 一次在调用子类型的构造函数中。
所谓寄生组合继承,即通过借用构造函数继承属性,通过原型链混成的方式来继承方法。
其背后的思想是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已,本质上就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
function inheritPrototypetype(SubType,SuperType){
var prototype = object(SuperType.prototype);
prototype.constructor = SubType;
SubType.prototype = prototype;
}
寄生组合继承的高效之处就是只调用了一次超类型构造函数。