很多面向对象语言都支持两种继承:接口继承和实现继承,前者继承方法签名,后者继承实际的方法。接口继承在 ECMAScript 中不可能实现,因为 函数没有签名。实现继承是 ECMAScript 唯一支持的继承方式,主要通过原型链实现。
1、原型链
基本思想:通过原型继承多个引用类型的属性和方法。
原型与继承的关系:
通过两种方式来确定:
- instanceof 操作符 eg: obj instanceof Object // true
原理: instanceof 运算符用于测试构造函数的 prototype 属性是否出现在对象原型链中的任何位置。- isPrototypeOf 方法 eg: Object.prototye.isPrototypeOf(obj) // true
存在问题:
- 原型中包含引用值的时候,会在所有实例间共享,可能会被实例所改变,影响所有的实例对象。基本类型不会被改变,只会在实例本身创建一个新的属性。
- 子类型在实例化时不能给父类型的构造函数传参。
2、盗用构造函数(经典继承)
基本思想:在子类构造函数中调用父类构造函数。
利用了apply 和 call 方法以新创建的对象为上下文执行构造函数。
优点:可以在子类构造函数中向父类构造函数传参(apply,call 接受参数)。
缺点:必须在构造函数中定义方法,函数不能重用,此外子类也不能访问父类原型上定义的方法。
3、组合继承(伪经典继承)
基本思想:使用原型链继承原型上的属性和方法,通过盗用构造函数继承实例属性。
组合继承弥补了原型链和盗用构造函数的不足,也保留了 instanceof 操作符 和 isPrototypeOf 方法识别合成对象的能力。
4、原型式继承
是一种不涉及严格意义上构造函数的继承方法。出发点是即使不自定义类型也可通过原型实现对象之间的信息共享。
ECMAScript5 通过增加 Object.create() 方法将原型式继承的概念规范化,接受两个参数:作为新对象原型的对象, 以及给新对象定义额外属性的对象。
原型式继承继承非常适合不需要单独创建构造函数,但仍需要在对象间共享信息的场合。属性中包含的引用值始终会在相关对象间共享,与原型模式一样。
5、寄生式继承
基本思路:创建一个实现继承的函数,以某种方式增强对象,然后返回这个对象。
寄生式继承同样适合主要关注对象,而不在乎类型和构造函数的场景。
缺点:通过寄生式继承给对象添加函数会导致函数难以重用。与构造函数模式类似。
6、寄生式组合继承
组合式继承存在效率问题:在指定子类原型对象时调用一次,在实例化子类时调用父类构造函数一次。(调用了两次)
寄生式组合继承通过盗用构造函数继承属性,但是用混合式原型链继承方法。
基本思路:不通过调用父类构造函数给子类原型赋值,而是取得父类原型的一个副本。就是使用寄生式继承来继承父类原型,然后将返回的新对象赋值给子类原型。
寄生式组合继承式是引用类型继承的最佳模式。
网友评论