JS继承的几种方式

243 阅读2分钟

原型继承

  • 子类的prototype指向了一个父类实例
      //父类 Peroson 构造函数
      function Person(name,age){
          this.name = name
          this.age = age
      }
      ​
      Person.prototype.sayHi = function(){
          console.log('你好啊');
      }
      ​
      //子类 Student 构造函数
      function Student(id){
          this.id = id
      }
      ​
      //改变原型链指向,实现继承
      Student.prototype = new Person('小明',12)
      ​
      let stu1 = new Student("666")
      stu1.name = '李四'
      stu1.age = 12
      let stu2 = new Student("888")
    

优缺点

优点:

  • 简单易于实现,父类的新增的实例与属性子类都能访问 缺点:
  • 无法实现多继承
  • 创建子类实例时,不能向父类构造函数中传参数
  • 原型属性上的引用类型值会被所有实例共享

借用构造函数继承

  • 只能继承属性,继承不了方法

      //父类 Peroson 构造函数
      function Person(name,age){
          this.name = name
          this.age = age
      }
      ​
      Person.prototype.sayHi = function(){
          console.log('你好啊');
      }
      ​
      //子类 Student 构造函数
      function Student(name,age,id){
          //借用构造函数继承
          Person.call(this,name,age)
          this.id = id
      }
      ​
      //初始化学生实例
      let stu1 = new Student('lisi',19,'20210729')
      stu1.sayHi() #报错stu1.sayHi is not a function
    

组合式继承(伪经典继承)

原型继承 + 原型继承

调用了两次父类构造函数,生成了两份实例

  //父类 Peroson 构造函数
  function Person(name,age){
      this.name = name
      this.age = age
  }
  ​
  Person.prototype.sayHi = function(){
      console.log('你好啊');
  }
  ​
  //子类 Student 构造函数
  function Student(name,age,id){
      Person.call(this,name,age)
      this.id = id
  }
  ​
  //改变原型链指向
  Student.prototype = new Person('小明',12)
  let stu1 = new Student('张三',26,"666")
  ​
  console.log(stu1);

寄生组合继承(经典继承)

  • 解决组合式继承,父类构造函数调用两次的缺点

  • 依然有问题:改变了Student原型的指向,如果原先Student的原型上有方法,继承后是拿不到的,需要在改变指向后,再在原型上添加方法

      Student.prototype = Object.create(Person.prototype)
      # 返回一个对象,指定返回对象的原型使指定参数的原型
    
      //父类 Peroson
      function Person(name,age){
          this.name = name
          this.age = age
      }
      ​
      Person.prototype.sayHi = function(){
          console.log('你好啊');
      }
      ​
      //子类 Student 通过构造函数继承
      function Student(name,age,id){
          Person.call(this,name,age)
          this.id = id
      }
      ​
      //改变原型链指向
      //希望直接拿到Person的原型对象
      //Student.prototype = new Person('小明',12)
      //Object.create是ES5的语法,存在兼容性问题
      ​
      # 兼容性写法
      if(!Object.create){
          Object.create = function(proto){
              function F(){}
              F.prototype = proto
              return new F()
          }
      }
      Student.prototype = Object.create(Person.prototype)
      let stu1 = new Student('张三',26,"666")
      ​
      console.log(stu1);
    

圣杯模式继承

  • 解决寄生组合继承的缺点

ES6 extends 继承

class Person{
    constructor(name,age){
        this.name = name
        this.age = age
	}
    sayHi(){
    	console.log('Hello,world');  
    }
}

class Student extends Person{
    constructor(name,age,id){
        super(name,age)
        this.id = id
    }
}

let stu1 = new Student('李四',18,'123')
console.log(stu1);