6、原型继承和构造函数继承
原型继承
就是让类的prototype属性指向某个对象,这样该类的实例就能用它指向的那个对象的所有属性和方法。和C#的类继承差不多,子类可以用父类成员,只是js继承方法不一样,原型继承也是js中的一种继承方式
prototype就是原型,所有对象和类都有原型。如果是 function这种形式的类它的构造方法和类是它自己。
创建三个类
function Person(){
this.typeName="人类";
}
function Chinese(){
this.country="中国";
}
function SiChuanRen(){
this.province="四川人";
}
让Chinese的原型继承Person,SiChuanRen的原型继承Chinese,并实例化SiChuanRen这个类
Chinese.prototype=new Person();
SiChuanRen.prototype=new Chinese();
var sichuan=new SiChuanRen();
console.log(sichuan);
输出结果可以看到:SiChuanRen的对象的一级原型对象竟然不是Chinese,那是因为,先设置了Chinese的原型,那么此时Chinese的原型就是Person了,然后SiChuanRen去继承Chinese,发现Chinese已经有了原型,所以就去继承Chinese的原型了。
所以要先让SiChuanRen去继承Chinese
SiChuanRen.prototype=new Chinese();
Chinese.prototype=new Person();
var sichuan=new SiChuanRen();
console.log(sichuan);
这样SiChuanRen的一级继承原型就是Chinese
原型继承的优点和缺点
优点
1、实例的原型是父类的实例。如:
2、实例可以继承的属性有:实例自己的构造函数属性,父类的构造函数属性,新实例不会继承父类的属性
缺点
1、新实例无法向父类构造函数传参 ,因为整个实例的原型就是父类的实例,父类都实例化了,也就是都调过父类的构造函数了。如:
2、继承单一,因为原型只有一个,原型已经继承了一个了就无法再继承其它类了。
3、所有的子类新实例都会共享父类实例的属性。父类实例的属性指的就是子类的原型链属性,因为所有子类的原型都是同一个父类,所以定义在子类的原型对象里的属性所有实例都是共享的("类名.prototype.属性名"),一个实例修改了原型属性的值,另一个实例相对应的原型属性的值也会被修改。
构造函数继承
为了解决原型继承的缺点,就可以使用构造函数继承
声明父类
function Person(name){
this.username=name;
}
声明子类,让其继承父类
通过call()方法继承父类构造函数,本质上js没有继承这个概率,原型继承和构造函数继承都是模拟继承
function Chinese(){
Person.call(this,"中国人");
}
实例化子类,输出父类的属性
var chinese=new Chinese();
console.log(chinese.username);
也可以多级继承
function Person(name){
this.username=name;
}
function People(){
this.age=18;
}
function Chinese(){
Person.call(this,"中国人");
People.call(this);
}
var chinese=new Chinese();
console.log(chinese.username);
console.log(chinese.age);
如果People也有一个属性叫username的话,那么实例输出的username就是people类的username属性,因为继承两个类,相同属性会被覆盖掉。