前言:JS继承常规共有6种方法,分别:
1.原型链继承
2. 构造函数继承
3. 组合继承(原型链继承+构造函数继承)
4. 原型式继承
5. 寄生式继承
6. 寄生组合式继承
但是真正能使用的只有3和6两种继承而已,应为其他的继承方式都不是完整的继承多会有或多或少的欠缺,接下来就为大家讲解各个继承的详解
首先我们定义一个父类:
function Animal(name){
this.name = name;
}
Animal.prototype.sayName = function(){
console.log(this.name);
}
一、原型链继承
function Cat(age){
this.age = age;
}
Cat.prototype = new Animal("mao");
Cat.prototype.constructor = Cat;
const cat1 = new Cat(1);
const cat2 = new Cat(2);
首先,这里Cat.prototype为什么不直接等于Animal.prototype,而等于Animal实例是因为Animal.prototype是个对象(对象的赋值不会另外开辟一个空间,而是创建一个指针指向这个对象),所以当我们修改Cat.prototype时会连带修改了Animal.prototype。
缺点:
1.子类实例会共享父类实例属性(cat1修改__proto__的name,cat2的__proto__上的name同时会被修改)。
二、构造函数继承
function Cat(age){
Animal.call(this,"mao");
this.age = age;
}
const cat = new Cat(1);
注意这里:cat1 instanceof Animal为false。
缺点:
1.只继承了父类构造函数的属性,没有继承父类原型的属性。
2.无法实现构造函数的复用(每次子类调用都要重新调用父类构造函数),导致每个子类实例都有父类构造函数的副本,臃肿。
三、组合继承
function Cat(age){
Animal.call(this,"mao1");
this.age = age;
}
Cat.prototype = new Animal("mao2");
Cat.prototype.constructor = Cat;
const cat = new Cat();
缺点:
1.调用了两次父类构造函数(耗内存)。
2.子类构造函数会代替原型上的父类构造函数。(cat.name等于mao1而不等于mao2)
四、原型式继承
function medium(obj){
function F(){};
F.prototype = obj;
return new F()
}
let animal = medium(new Animal());
animal.age = 1; //定义animal私有属性
缺点:
1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
五、寄生式继承
function medium(obj){
function F(){};
F.prototype = obj;
return new F();
}
function subMedium(obj){
let sub = medium(obj);
sub.age = 1;
return sub;
}
let animal = subMedium(new Animal());
缺点:
1.没用到原型,无法复用。
六、寄生组合式继承
function medium(obj){
function F(){};
F.prototype = obj;
return new F();
}
function Cat(age){
Animal.call(this);
this.age = age;
}
const sub = medium(Animal.prototype);
Cat.prototype = sub;
sub.constructor = Cat;