JS中几种继承的方式及缺点
原型链继承
每个构造函数都有一个原型对象(通过prototype属性)
原型对象都包含一个指向构造函数的指针(通过constructor属性)
实例都包含一个指向原型对象的内部指针(通过隐式proto属性)
那么,若原型对象等于另一个原型的实例,则此时原型对象将包含一个指向另一个原型对象的指针。相应的另一个原型中也包含一个指向另一个构造函数的指针。如此层层递进,就构成了实例与原型的链条。
//父类
function Person(name){
this.name=name;
this.sum=function(){
console.log(this.name)
}
}
Person.prototype.age=10;
//原型链继承
function people(){
this.name='NAME';
}
people.prototype=new Person();
var people1=new people();
console.log(people1.age);
console.log(people1 instanceof Person);
缺点:
- 新实例无法向父类构造函数传参。
- 继承单一。
- 原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改。
构造函数继承
构造函数继承也叫伪造对象或经典继承,这种方式解决了原型链继承的问题,实例可以独享一份引用类型的值 ,通过call改变this指向,这样每次执行SuperType函数,this指向的都是新的对象。相当于每个新的对象都有一份完整的SuperType代码。即每个实例都有一份自己的colors属性副本。可以通过call函数向SuperType传参数。
//构造函数继承
function people(){
Person.call(this,'NAME');
this.age=12;
}
var people1=new people();
console.log(people1.name);
console.log(people1.age);
console.log(people1.instanceof Peerson);
缺点:只能继承父类构造函数的属性,无法实现构造函数的复用,每个新实例都有父类构造函数的副本,臃肿。
组合继承
也叫伪经典继承,它是最常用的的继承方式,组合继承将原型链继承和构造函数继承结合到一起,结合了两种模式的优点,传参和复用。
//组合继承
function people(name){
Person.call(this,name);
}
people.prototype=new Person();
var peo=new people('NAME');
console.log(peo.name);
console.log(peo.age);
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
原型式继承
借助原型可以基于已有的对象创建新对象,不必因此创建自定义类型。该方法与原型链继承类似,但是写法比它简单,若只是想让一个对象和另一个相似,可以使用这种方法。
//原型式继承
function people(obj){
function P(){}
P.prototype=obj;
return new P();
}
var peo=new Person();
var peo1=content(peo);
console.log(peo1.age);
缺点:包含引用类型值的属性始终共享相应的值。无法实现复用。
寄生式继承
没有创建自定义类型,因为只是套了个壳子返回对象,这个函数顺理成章就成了创建的新对象。
//寄生式继承
function content(obj){
function P(){}
P.prototype=obj;
return new P();
}
var sup=new Person();
function subobject(obj){
var sub=content(obj);
sub.name='gar';
return sub;
}
var sup2=subobject(sup);
console.log(typeof subobject);
console.log(typeof sup2);
console.log(sup2.name);
缺点:这样做相当于构造函数那样,并不是真正的函数复用。而且包含引用类型值的属性依然始终共享相应的值。
寄生组合式继承
寄生:在函数内返回对象然后调用。
组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参。
重点:修复了组合继承的问题。
//寄生
function content(obj){
function P(){}
P.prototype=obj;
return new P();
}
var con=content(Person.prototype);
//组合
function Sub(){
Person.call(this);
}
Sub.prototype=con;
con.constructor=Sub;
var sub1=new Sub();
console.log(sub1.age);