这里不谈原型式继承、寄生式继承以及寄生组合继承
1、原型链继承
//原型链继承:子类原型指向父类的实例对象
function People(){
this.name = '张三';
}
People.prototype.speak = function(){
console.log(this.name+'正在说话');
}
// 子类,目前和People类没有任何关系
function Child(){
this.grade = '10';
}
// 继承People类
// 用People实例对象作为Child类的原型
Child.prototype = new People()
let child = new Child()
child.speak()
优点:子类可以访问到父类的所有属性和方法
缺点:
- 创建子类实例对象的时候无法给父类的构造函数传参,
- 如果要给子类添加特有的原型属性只能在原型继承完成之后在添加,否则会被覆盖掉,
- 父类的引用类型属性会被所有子类共享,无法给各个子类单独创建副本,也就是说父类如果有一个Array类型的属性,所有子类都会共享这个属性
2、构造函数继承
// 构造函数继承
function People(name,father,mother){
this.name = name;
this.parents = [father,mother]
this.speak = function(){
console.log('speak');
}
}
// 子类的构造函数调用父类的构造函数
function Child(name,father,mother){
People.call(this,name,father,mother)
}
优点:
- 可以向父类构造函数传参
- 避免了引用类型的属性被所有实例共享带来的问题
缺点:
- 无法获取父类原型对象上的属性和方法,因为子类的原型对象和父类的原型对象没啥关系
- 父类构造函数中的实例方法无法实现复用,每次创建子类实例的时候都会创建一次父类构造函数中的所有实例方法,如speak方法。
3、组合继承
// 组合式继承
function People(name,father,mother){
this.name = name;
this.parents = [father,mother]
}
People.prototype.speak = function(){
console.log('speak');
}
// 子类的构造函数调用父类的构造函数
function Child(name,father,mother){
People.call(this,name,father,mother)
}
// 获取父类原型对象上的属性和方法
Child.prototype = new People();
优点:解决了原型链继承和构造函数继承的缺陷
缺点:组合继承最大的缺点是会调用两次父构造函数。(People.call和new People)