继承
实现继承:继承实际的方法。ECMAScript 只支持实现继承,而且其实现基础主要是依靠原型链来实现的。
基本思想是:利用原型来实现一个引用类型继承另外一个引用类型的属性和方法。
原型 - 构造函数 - 实例 之间的关系
构造函数(prototype) <-------> 原型(constructor) <------- 实例(_proto_)
实现原型链有一种基本模式,其代码大致如下
1 function SuperType(){ 2 3 this.property = true; 4 } 5 6 SuperType.prototype.getSuperValue = function(){ 7 return this.prototype; 8 } 9 function SubType(){ 10 this.subproperty = false; 11 } 12 13 //继承了SuperType 14 15 SubType.prototype = new SuperType(); 16 17 SubType.prototype.getSubValue = function(){ 18 return this.subproperty; 19 } 20 21 var instance = new SubType(); 22 alert(instance.getSuperValue()); 23 24 25 function SuperType(){ 26 this.property = true; 27 } 28 29 SuperType.prototype.getSuperValue = function(){ 30 return this.property; 31 } 32 33 function SubType(){ 34 this.subproperty = false; 35 } 36 SubType.prototype = new SuperType(); 37 38 SubType.property = { 39 getSubValue:function(){ 40 return this.subproperty; 41 }, 42 someOtherMethod:function(){ 43 return false; 44 } 45 } 46 47 var instance = new SubType(); 48 alert(instance.getSuperValue());
6.3.1 既在通过原型进行继承时,不能使用字面量的方法创建原型内容,因为这样会重写原型链
原型中存在的最大问题是:
1 引用类型值得共用问题
2 用原型实现的继承,由于属性共用,在创建子类型实例时,不能向超类型的构造函数中传递参数。
6.3.2 借用构造函数
call() apply()
在解决原型中包含引用类型值所带来问题的过程中,可以使用一种叫借用构造函数的技术(有时候也叫做伪造对象或经典继承)。这种技术的基本思想相当简单,既在子类型构造函数的内部调用超类型构造函数。别忘了,函数
只不过是在特定环境中执行代码的对象,因此通过使用apply()和 call()方法也可以在新创建的对象上执行构造函数,
function SuperType(){ this.colors = ["red","blue","green"]; } function SubType(){ SuperType.call(this); } var instance = new SubType(); instance.colors.push("black"); alert(instance.colors); //red blue green black var instance1 = new SubType(); alert(instance1.colors); // red blue green
借用构造函数相比原型模式的优点:
· 传递参数
例如:
function SuperType(name){ this.name = name; } function SubType(){ SuperType.call(this,"Nicholas"); this.age = 20; } var instance = new SubType(); alert(instance.name); // Nicholas alert(instance.age); //20
借用构造函数的问题
如果仅仅是借用构造函数,那么也将无法避免构造函数模式存在的问题------ 方法都在构造函数中定义,因此函数复用就无从谈起了。
6.3.3
组合继承(combination inheritance) 原型与借用构造函数两种方法取其长的一种组合方式
主要思想:
利用原型对属性和方法的继承 而通过借用构造函数来实现对实例属性的继承。
这样既然继承原型中属性,又能保证实例拥有自己的属性。
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",20); instance1.colors.push("black"); alert(instance1.colors); instance1.sayName(); instance1.sayAge(); var instance2 = new SubType("Greg",27); alert(instance2.colors); instance2.sayName(); instance2.sayAge
在这个例子中,SuperType 构造函数定义了两个属性: name 和 colors. SuperType的原型定义了一个方法sayName(). SubType()构造函数在调用 SuperType 构造函数时传入了name参数,紧接着又定义了它自己的属性age。
然后,将SuperType的实例赋值给SubType的原型,然后又在新原型上定义了方法sayAge(). 这样一来,就可以让两个不同的SubType实例既分别拥有自己的属性----包括colors 属性,又可以使用相同的方法了。
组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点。 而且 instanceof 和 isPrototypeOf 也能够用于识别基于组合继承创建的对象。