咱们都知道,面向对象的编程语言很是强大,之因此强大,就是其支持继承。在JavaScript中,也支持继承,并且有多种方法实现继承,好比原型链继承,借用构造函数继承,或者把原型链和借用构造函数函数组合在一块儿的组合继承,还有直接原型式继承,深浅拷贝继承。下面我就一一来讲一说这些继承方法。javascript
首先咱们得清楚构造函数(constructor),原型对象(prototype)和实例的三者关系。html
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。java
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //inherit from SuperType SubType.prototype = new SuperType();//重写原型对象,赋值为一个实例对象,得到实例对象的全部属性和方法 SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true
原型链的详细请看深刻理解原型链一文编程
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ //inherit from SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green"
经过借用构造函数的方法,会实现对实例属性的继承,每一个实例都有它本身的属性,这些属性都是部署在本身身上的,每个实例对象都有本身的一个副本。改变属性不会对其它实例对象的该属性形成影响。数组
组合继承,有时候也叫伪经典继承,指的是将原型链和借用构造函数的技术组合到一块,从而发挥两者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而经过借用构造函数来实现对实例属性的继承。这样既经过在原型上定义方法实现了函数复用,又可以保证每一个实例都有它本身的属性。编程语言
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.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(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27`
原型式继承并无使用严格意义上的构造函数,而是借助原型能够基于已有的对象建立新对象,同时还没必要建立自定义类型。函数
function object(o) { function F() {} F.prototype = o; return new F(); }
在object()函数内部,先建立了一个临时性的构造函数,而后将传入的对象做为这个构造函数的原型,最后返回了这个临时类型的一个新实例。本质上,是对传入其中的对象作了一次浅拷贝。this
实例prototype
function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
原型式继承要求你必须有一个对象做为另外一个对象的基础,经过把一个对象传递给object()函数,而后再根据具体需求对获得的对象加以修改(修改原来的,或者添加新的属性方法)便可。指针
在ECMAScript5中,新增了一个Object.create()方法规范了原型式继承,这个方法接受两个参数:一个用做新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的状况下,Object.create()与object()方法的行为相同。
实例
var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = Object.create(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"