一、你必须知道的
1> 原型及原型链在继承中起到了关键的作用。所以你一定要理解他们。2> 不会JS中的OOP,你也太菜了吧!(第一篇)
二、继承的6种方法
1> 原型链继承
原型链继承是通过创建Super的实例,并将该实例赋值给Sub.prototype来实现的。
实现的本质是:重写子类型的原型对象,代之以超类型的实例。
function Super(){
this.name = 'JChen___';
}
Super.prototype.getSuperName = function(){
return this.name;
} function Sub(){
this.subname = 'JChen___son';
}
Sub.prototype = new Super(); //原型继承体现在这里
Sub.prototype.getSubName = function(){
return this.subname;
} var instance = new Sub();
注意:此时instance.constructor现在指向的是Super的,这是因为Sub.prototype指向了Super.prototype,而Super.prototype.constructor = Super。
原型链的问题:类似于利用原型创建对象,原型共享的特性也是原型链继承的最大问题。
2> 借用构造函数继承
在解决原型中包含引用类型值所带来的问题的过程中,我们开始使用一种叫做借用构造函数的技术。
这种技术的基本思想相当简单:在子类型构造函数的内部调用超类型构造函数。
这样一来,就会在新子类对象上执行超类函数中定义的所有对象初始化代码。结果,每个子类的实力都会有自己的超类中属性的副本了。
function Super2(name){
this.colors = ['red', 'blue'];
this.name = name;
} function Sub2(){
Super2.call(this, 'JChen___2'); //借用构造函数技术体现在这里
this.age = 29;
} var instance1 = new Sub2();
instance1.colors.push('black');
var instance2 = new Sub2();
instance2.colors.push('green');
借助构造函数继承的问题:
1): 方法都在构造函数中定义,无法复用。
2): 在超类型的原型中的方法对子类是不可见的。
3> 组合继承(原型+借用构造)
组合继承指的是将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。
组合继承的思路:使用原型链实现对方法和属性的继承,通过借用构造函数实现对实例属性的继承。
function Super3(name){
this.name = name;
this.colors = ['red', 'blue'];
}
Super3.prototype.sayName = function(){
return this.name;
} function Sub3(name, age) {
Super3.call(this, name);
this.age = age;
}
Sub3.prototype = new Super3(); //解决借用构造函数技术的缺点
Sub3.prototype.constructor = Sub3; //纠正原型继承改变了的构造函数
Sub3.prototype.sayAge = function(){
return this.age;
}
组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,成为JavaScript中最常用的继承模式。
组合继承的问题:两次调用超类构造函数。
4> 原型式继承
原型式继承的思路:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
function object(o){ //原型式继承的关键
function F(){}
F.prototype = o;
return new F();
}
var person = {
name: 'JChen___4',
colors: ['blue']
}
var person1 = object(person);
person1.name = 'JChen___4___2'
person1.colors.push('red');
var person2 = object(person);
person2.name = 'JChen___4___3';
person2.colors.push('green');
原型式继承的问题:同原型链一样,他也有共享的劣势。
5> 寄生式继承
寄生式继承的思路:创建一个仅用于封装继承过程的函数,该函数内部以某种方式来增强对象,最后再返回该对象
function createAnother(origin){ //寄生式继承的关键
var clone = object(origin);
clone.sayHi = function(){
return 'Hi';
};
return clone;
}
var person = {
name: 'JChen___4',
colors: ['blue']
}
var person1 = createAnother(person);
寄生式继承的问题:像构造函数一样,由于不能做到函数的复用而降低效率。
6> 寄生组合式继承
寄生组合式继承:通过借用构造函数来借用属性,通过原型链的混成形式来继承方法。
其背后的思想是:不必为了指定子类型的原型而调用超类型的构造函数,我们需要的无非就是超类型的一个副本而已。
function object(o){
function F(){}
F.prototype = o;
return new F();
}
function inheritProto(subType, superType){ //避免第一调用构造函数的关键
var proto = object(superType.prototype);
proto.constructor = subType;
subType.prototype = proto;
} function Super6(name){
this.name = name;
this.colors = ['red', 'blue'];
}
Super6.prototype.sayName = function(){
return this.name;
} function Sub6(name, age){
Super6.call(this, name);
this.age = age;
} inheritProto(Sub6, Super6); Sub6.prototype.sayAge = function(){
return this.age;
} var instance1 = new Sub6('JChen___6', '12');
instance1.colors.push('black');
开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
三、总结
这就是JavaScript中的6种继承方式,如果大家能够画出每个继承的原型链关系图,那么继承就是小菜一碟了。