1,介绍
- ECMAScript实现继承依靠原型链来实现的。
2,原型链
- 基本思想
原型链的基本思想是利用原型让一个引用类型继承另一个另一个引用类型的属性和方法。 - 基本概念
假如我们让原型对象等于另一个类型的实例,显然,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个实例中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例和原型的链条。 代码大致如下:
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; } function SubType(){ this.subproperty = false; } // 继承了SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function(){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true
- 图表实例
完整的原型链
- 确定原型和实例的关系
使用instanceof操作符和isPrototypeOf()方法,只要是原型链中出现过的原型,都可以说说是该原型链所派生的实例的原型。 - 原型链的问题
最主要的问题来自包含引用类型值的原型。
3,借用构造函数
- 介绍
在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数的技术,有时也叫做伪造对象或经典继承。 方式
在子类型构造函数的内部调用超类型构造函数。示例:function SuperType(){ this.colors = ["red","blue","green"]; } function SubType(){ SuperType.call(this); } var instancel = new SubType(); instancel.colors.push("black"); alert(instancel.colors); // "red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); // "red,blue,ggreen"
- 借用构造函数的问题
方法都在构造函数中定义,因此函数就不能复用。而且在超类型的原型中定义的方法,对子类型而言也是不可见的,结果所有类型都只能使用构造函数模式。考虑到这些问题,借用构造函数的技术也是很少单独使用。
4,组合继承
- 介绍
- 有时也叫伪经典继承,指的是将原型链和借用构造函数的技术组合到一块,从而发挥各自之长的一种继承模式。
- 使用原型链实现对原型属性的继承,而通过构造函数实现对实例属性的继承。
代码示例:
function SuperType(name){ this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function(){ alert(this.name); } function SubType(name,age){ SuperType.call(this,name); this.age = age; } SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); } var instance1 = new SubType("Nicholas",29); instance1.colors.push("black"); alert(instance1.colors); // red,blue,green,black instance1.sayName(); // Nicholas instance1.sayAge(); var instance2 = new SubType("Greg",27); alert(instance2.colors); // red,blue,green instance2.sayName(); // Greg instance2.sayAge(); // 27
- 总结
- 组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,成为JavaScript中最常用的继承模式。
- instanceof和isPrototypeOf()也能够用于识别基于组合继承创建的对象。
5,原型式继承
介绍
借助原型基于已有的对象创建新对象。可以给出如下函数:
function object(o){ function F(){} F.prototype = o; return new F(); }
使用obect()函数示例代码
var person = { name:"Nicholas", friends:["Shelby","Court","Van"] }; var anotherPerson = obect(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.push("Barbie"); alert(person.friends) // "Shelby,Court,Van,Rob,Barbie"
思想分析
这种原型式继承,要求必须要有一个对象可以作为另一个对象的基础,可以把它传递给object()函数,创建person对象的副本。
- Object.create()
ECMAScript 5新增的方法规范了原型继承这个方法接受两个参数,如下:
- 用作新对象原型的对象
- 一个为新对象定义额外属性的对象。与Object.defineProperties()方法的第二个参数格式相同。
6,寄生式继承
- 介绍
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数。 - 特点
使用寄生式继承来为对象添加函数,会由于不能做到函数复用而降低效率;这一点与构造函数模式类似。
7,寄生组合式继承
介绍
通过借用构造函数来继承属性,通过原型链的换成形式来继承方法,其背后的基本思路是:不必为指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。寄生组合式继承的基本模式如下所示:function inheritPrototype(subType,superTpye){ var prototype = Object(superType,superType); prototype.constructor = subType; subType.prototype = prototype; }
用代码说话
function SuperType(name){ this.name = name; this.colors = ["red","blue","green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name,age){ SuperType.call(this,name); this.age = age; } inheritPrototype(SubType,SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };
- 总结
寄生组合式继承是引用类型最理想的继承范式。