原型链继承
理解原型链的概念
用一张图来理解原型链再合适不过了。
总结概括JS红宝书上对原型链的概念:每个函数都有一个prototype属性,它指向原型对象。每一个实例都有一个 proto 属性,它指向该实例的原型对象。如果把一个实例的原型对象再次看作一个实例,它也就会有一个 proto 属性,这个属性指向它的原型对象。
这样我们可以知道,JS原型链其实是靠proto 属性来实现的。
实现继承
实现原型链继承有一种基本模式:
提醒:通过原型链实现继承时,不能使用对象字面量创建原型方法。这样会重写原型链。
确定原型和实例的关系
使用instanceof操作符。
123alert(instance instanceof Object); //truealert(instance instanceof SuperType); //truealert(instance instanceof SubType); //true使用isPrototypeOf()方法
123Object.prototype.isPrototypeOf(instance); //trueSuperType.prototype.isPrototypeOf(instance); //trueSubType.prototype.isPrototypeOf(instance); //true
原型链的问题
- 对于引用类型值的原型,原型链继承的方法会导致实例共享引用类型的原型。所以属性定义最好在构造函数中而不是原型中。
- 在创建子类型的实例时,不能向超类型的构造函数中传递参数。
构造函数继承
实现方法
|
|
构造函数的问题
方法都在构造函数中定义,因此函数复用就无从谈起。
组合继承
将原型链和借用构造函数的技术组合起来,发挥二者之长的一种继承模式。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
原型式继承
实例
|
|
这种原型式继承,要求你必须有一个对象可以作为另一个对象的基础。如果有这么一个对象的话,可以把它传递给object函数,然后再根据具体的需求对得到的对象加以修饰即可。
规范化
ECMAScript5通过新增Object.create()方法规范化了原型式继承。
|
|
寄生式继承
与寄生构造函数和工厂模式类似,创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。
在上述例子中,createAnother函数接收了一个参数,也就是将要作为新对象基础的对象。
anotherPerson是基于person创建的一个新对象,新对象不仅具有person的所有属性和方法,还有自己的sayHi()方法。
寄生组合式继承
组合继承是js最常用的继承模式,组合继承最大的问题就是无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型时,另一次是在子类型构造函数内部。
组合继承的问题
|
|
在第一次调用SuperType构造函数时,SubType.prototype会得到两个属性: name和colors; 他们都是SuperType的实例属性,只不过现在位于SubType的原型中。
当调用SubType构造函数时,又会调用一次SuperType构造函数,这一次又在新对象上创建了实例属性name和colors。
于是这两个属性就屏蔽了原型中的两个同名属性。
解决方案
寄生组合式继承就是为了解决这一问题。
通过借用构造函数来继承属性;
通过原型链来继承方法。
不必为了指定子类型的原型而调用超类型的构造函数
inheritPrototype函数接收两个参数:子类型构造函数和超类型构造函数。
- 创建超类型原型的副本。
- 为创建的副本添加constructor属性,弥补因重写原型而失去的默认的constructor属性
- 将新创建的对象(即副本)赋值给子类型的原型
这种方法只调用了一次SuperType构造函数,instanceof 和isPrototypeOf()也能正常使用。