一、原型链继承

核心:将父类的实例作为子类的原型,主要是利用了Dog.prototype = new Animal(),这样Dog.prototype.proto就指向了Animal.prototype,从而将子类Dog的原型和父类Animal的原型相关联

  1. function Animal() {
  2. this.name = 'animal'
  3. this.arr = []
  4. this.eat = function() {
  5. console.log('animal eat')
  6. }
  7. }
  8. Animal.prototype.age = 18
  9. function Dog() {
  10. this.break = function() {
  11. console.log('dog bark');
  12. }
  13. }
  14. // Dog.prototype.__proto__ = Animal.prototype
  15. // Dog.prototype 指向 Animal的实例
  16. Dog.prototype = new Animal();
  17. // h1.__proto__ = Dog.prototype
  18. let h1 = new Dog();
  19. console.log(h1.arr)
  20. h1.arr.push(1)
  21. let h2 = new Dog();
  22. console.log(h2.arr)

特点:

  1. 非常纯粹的继承关系,实例是子类的实例,也是父类的实例
  2. 父类新增原型方法/原型属性,子类都能访问到

缺点:
来自父类引用类型的实例属性是所有实例共享的,即属性没有私有化,原型上属性的改变会作用到所有的实例上

二、构造函数继承

核心:在调用子类构造函数时内部使用call或apply来调用父类的构造函数,从而达到了使用父类的的构造函数来增强子类实例的效果,等于是复制父类的实例属性给子类(没有用到原型)

  1. function Super(){
  2. this.flag = true;
  3. }
  4. function Sub(){
  5. Super.call(this) //如果父类可以需要接收参数,这里也可以直接传递
  6. }
  7. var obj = new Sub();

特点:
1. 实现了属性的私有化
2. 创建子类实例时,可以向父类传递参数
3. 可以实现多继承(call多个父类对象)
缺点:
1. 实例并不是父类的实例,只是子类的实例
2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能

三、组合继承

核心:结合了构造函数继承和原型链继承

  1. function Super(){
  2. this.flag = true;
  3. }
  4. Super.prototype.getFlag = function(){
  5. return this.flag; // 继承方法
  6. }
  7. function Sub(){
  8. this.subFlag = flase
  9. Super.call(this) // 继承属性
  10. }
  11. Sub.prototype = new Super();
  12. var obj = new Sub();
  13. // Sub.prototype = new Super(); 会导致Sub.prototype的constructor指向Super;
  14. // 然而constructor的定义是要指向原型属性对应的构造函数的,Sub.prototype是Sub构造函数的原型,
  15. // 所以应该添加一句纠正:Sub.prototype.constructor = Sub;
  16. Sub.prototype.constructor = Sub; // 修复构造函数指向
  17. Super.prototype.getSubFlag = function(){
  18. return this.flag;
  19. }