ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的。
原型链:
利用原型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,假如我们**让原型对象等于另一个类型的实例**,结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。这就是原型链的基本概念。
单独使用原型链继承和构造函数继承有很多缺点。于是有人将原型链和借用构造函数的技术结合到一起,有了组合继承。是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性。看下面代码:
**组合继承代码**
function Parent(name){
this.name = name;
this.colors = ["red", "blue"];
}
Parent.prototype.sayHi = function(){
alert(this.name);
}
function Child(name, age){
Parent.call(this, name);//在这里通过call方法,改变Parent函数this的指向,使Child获得Parent的属性。
this.age = age;
}
Child.prototype = new Parent();//在这里将Child的原型重写为Parent的实例,继承Parent的方法
Child.prototype.constructor = Child;
这样做有个问题,就是会调用两次Parent构造函数,对性能的损耗会多一点。
于是,有人提出了寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
寄生组合式继承
function inheritPrototype(child, parent){
var prototype = object(parent.prototype); //创建对象
prototype.constructor = child; //增强对象
child.prototype = prototype; //指定对象
}
function Parent(name){
this.name = name;
this.colors = ["red", "blue"];
}
Parent.prototype.sayHi = function(){
alert(this.name);
}
function Child(name, age){
Parent.call(this, name);//在这里通过call方法,改变Parent函数this的指向,使Child获得Parent的属性。
this.age = age;
}
inheritPrototype(Child,Parent);
Child.prototype.constructor = Child;