继承是面向对象语言一个很是重要的部分。许多OOP语言都支持接口继承和实现继承两种方式。接口继承:继承方法签名;实现继承:继承实际的方法。在ECMAScript中函数是没有签名的,因此也就没法实现接口继承,只能支持实现继承。编程
在JavaScript中有大概六种继承方式,它们分别是:原型链继承,借用构造函数继承,组合继承,原型式继承,寄生式继承和寄生组合式继承。下面就是对着六种继承方式的详细介绍。函数
基本思想是利用原型让一个引用类型继承另外一个引用类型的属性和方法。在这里还得补充一下,每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。测试
function BasicType() { this.property=true; this.getBasicValue = function(){ return this.property; }; } function NewType() { this.subproperty=false; } NewType.prototype = new BasicType(); var test = new NewType(); alert(test.getBasicValue()); //true
由上面能够知道,其本质上是重写了原型对象,代之一个新类型的实例。在经过原型链继承的状况下,要访问一个实例属性时,要通过三个步骤:1搜索实例;2搜索NewType.prototype;3搜索BasicType.prototype,此时才找到方法。若是找不到属性或者方法,会一直向上回溯到末端才会中止。要想肯定实例和原型的关系,可使用instanceof和isPrototypeof()测试,只要是原型链中出现过的原型,均可以说是该原型链所派生实例的原型。还有一点须要注意,经过原型链实现继承时,不能使用对象字面量建立原型方法,由于这时会重写原型链,原型链会被截断。this
其大致思路是,在子类型构造函数的内部调用超类型构造函数。spa
function BasicType(name) {
this.name=name; this.color=["red","blue","green"]; } function NewType() { BasicType.call(this,"syf");
this.age=23; } var test = new NewType();
alert(text.name); //syf
alert(text.age); //23
这种继承实现方式有一种优点就是,能够在子类型构造函数中向超类型构造函数中传递参数,其缺点是不能进行函数复用。prototype
组合继承就是将原型链和借用构造函数继承模式结合起来,从而具备两者优点的方法。其理念是使用原型链实现对原型属性和方法的继承,经过借用构造函数来实现对实例属性的继承。指针
function BasicType(name) { this.name=name; this.colors=["red","blue","green"]; } BasicType.prototype.sayName=function(){ alert(this.name); } function NewType(name,age) { BasicType.call(this,name); this.age=age; } var test = new NewType("syf","23"); test.colors.push("black"); alert(test.colors); //"red,blue,green,black" alert(test.name); //"syf" alert(test.age); //23
组合式继承避免了原型链和借用构造函数继承方式的缺陷,融合了他们的优势,成为了js中最经常使用的继承方式。code
原型链继承和原型式继承只有一字之差,但他们的机理仍是有所差异的。原型式继承是借助于已有的对象来建立新对象,也就是必须有一个对象能够做为另一个对象的基础。继承方式函数表达为:对象
function object (o) { function F(){} F.prototype = o; return new F(); }
咱们能够在o的基础上进行修改,来建立特定的对象。直观上来讲,其与原型链继承最大的不一样之处就是没有使用new操做符。blog
寄生式继承的思路与寄生构造函数和工厂模式相似,即建立一个仅用于封装继承过程的函数,该函数在内部以某种方式来继承对象,最后再返回对象。具体为:
function createAnother ( original ){ var clone = object (original); //经过调用函数建立一个新对象 clone.sayHi=function(){ //以某种方式来加强这个对象 alert("hi"); }; return clone; //返回对象 }
在主要考虑对象而不是自定义类型和构造函数的状况下,寄生式继承也是一种有用的模式。使用寄生式继承来为对象添加函数,函数复用率低。
上面提到组合式继承,其也是JS里最经常使用的基础模式。但,因为其会调用两次超类型的构造函数:一次在建立子类型的时候,另外一次是在子类型构造函数内部。也就是子类型最终会包含超类型的所有实例属性,但在调用子类型构造函数时会重写这些属性。寄生组合式继承的大体思路为:经过借用构造函数来继承属性,经过原型链的混成形式来继承方法。也就是说,没必要为了指定子类型的原型而调用超类型的构造函数,咱们须要的是超类型原型的一个副本而已。本质上就是,使用寄生式继承来继承超类型的原型,而后再将结果指定给子类型的原型。基本模式以下:
function inheritPrototype (subType ,superType){ var prototype = object (superType.prototype); //建立对象,建立超类型原型的一个副本 prototype.constructor = subType; //加强对象,为建立的副本添加constructor属性
subType.prototype = prototype; //指定对象,将新建立的对象赋值给子类型的原型
}
因为寄生组合式继承弥补了组合式继承缺点,因此也被众多开发者认为是最理想的继承方式。
以上就是JS里的六种继承方式的介绍,在编程实践中具体选取哪一种方式还要根据当时状况来断定,适合的才是最好的,并必定非得使用组合式继承或者寄生组合式继承来完成继承。