首先回顾一下构造函数、原型和实例的关系:
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针
在JS中,实现继承主要是依靠原型链来实现;
基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。
一、原型链
1.1 概念
假设让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。
首先原型链的基本模式代码如下
function FatherType(){
this.property = true;
}
FatherType.prototype.getFatherValue = function(){
return this.property;
};
function SonType(){
this.sonproperty = false;
}
SonType.prototype = new FatherType(); //继承了 FatherType
SonType.prototype.getsonValue = function (){
return this.sonproperty ;
};
var son1= new SonType();
alert(instance.getFatherValue()); //true

1.2 原型搜索机制
当以读取模式访问一个实例属性时,首先会在实例中搜索该属性。如果没有找到该属性,则会继续搜索实例的原型
在通过原型实现继承的情况下,搜索过程就要沿着原型链继续向上。就拿图例来说,调用son1.getFatherValue()会精力三个搜索步骤:①搜索实例; ② 搜索 SonType.prototype; ③ 搜索 FatherType.prototype,最后一步才会找到该方法。在找不到属性或或方法的情况下,搜索过程要向上到原型链末端才会停下,若还找不到,返回null
1.3 原型链中要注意的三点
1、默认的原型Object
所有引用类型默认继承Object(通过原型链实现)。即所有函数的默认原型都是Object的实例,默认原型都会包含一个内部指针,指向Object.prototype。这也正是所有自定义类型都会继承 toString() 、valueOf() 等默认方法的根本原因。
2、确定原型和实例的关系
有两种方式,instanceof 、isPrototypeOf()
alert(son1 instanceof Object); //true
alert(son1 instanceof FatherType); //true
alert(son1 instanceof SonType); //true
alert(Object.prototype.isPrototypeOf(son1)); //true
alert(FatherType.prototype.isPrototypeOf(son1)); //true
alert(SonType.prototype.isPrototypeOf(son1)); //true
3、定义在原型上的方法要谨慎
- 给子类原型添加方法的代码要放在继承父类原型之后,否则方法无效
- 通过原型链实现继承后,不能使用对象字面量给子类原型上添加方法,这会导致重写原型链,继承无效
1.4 原型链实现继承的缺点
1、若父类的原型包含引用类型值的属性,子类的所有实例共享这个属性
2、在创建子类型的实例时,不能向父类型的构造函数中传递参数
二、借用构造函数
概念:在子类型构造函数的内部调用父类型构造函数
function FatherType(){
this.colors = ["red", "blue", "green"];
}
function SonType(){
FatherType.call(this); //继承了 FatherType
}
var instance1 = new SonType();
sob1.colors.push("black");
alert(son1.colors); //"red,blue,green,black"
var son2= new SubType();
alert(son2.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.constructor = SubType;
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
组合继承的优点:结合了原型链和借用构造函数的优点,既通过在原型上sing一方法实现了函数复用,又能保证每个实例都有自己的属性。
参考:《JS高级程序设计》
来源:CSDN
作者:君-
链接:https://blog.csdn.net/weixin_39307273/article/details/104224353