JS之对象继承

95 阅读1分钟

(1)原型链继承

实例对象数据是共享的,容易造成修改的混乱,并且在创建子类型的时候不能向超类型传递参数

    function Animal(){}
    Animal.prototype.age = 3
    Animal.prototype.sing = function(name){
        console.log(`我是${this.name},我会唱歌`)
    }
    function Cat(name){
        this.name = name
    }
    // 原型直接赋值实现继承
    // Cat.prototype = new Animal() 等同于下面的
    Cat.prototype = Animal.prototype
    
    let c1 = new Cat('小橘')
    c1.sing() // 我是小橘,我会唱歌
    console.log(c1.age) // 3
    // 此时我们再创建一个小狗,也继承 Animal 的原型
     function Dog(name){
        this.name = name
    }
    Dog.prototype = Animal.prototype
    let c2 = new Dog('哈士奇')
    console.log(c2.age) // 3
    
    // 但当我们修改 cat 上的 age 时,dog 也会随之改变
    Cat.prototype.age = 4
    console.log(c1.age) // 4
    console.log(c2.age) // 4
    // 缺点:由此可见,实例对象所共享, 容易造成修改的混乱

(2)构造函数继承

此方法解决了不能向超类型传递参数的缺点,但方法都在构造函数中定义,无法实现复用,并且超类型原型定义的方法子类型也没有办法访问到

    function Animal(name){
        this.name = name
        this.sing = function(name){
            console.log(`我是${this.name},我会唱歌`)
        }
    }
    // 子类调用超类型构造函数,通过 call 绑定this,传递参数
    function Cat(name){
       Animal.call(this,name)
    }
    let c3 = new Cat('大橘')
    c3.sing() // 我是大橘,我会唱歌

(3)组合继承(原型 + 构造函数)

通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承

    function Animal(name){
        this.name = name
    }
    Animal.prototype.sing = function(name){
        console.log(`我是${this.name},我会唱歌`)
    }
    // 子类调用超类型构造函数,通过 call 绑定this,传递参数
    function Cat(name){
       Animal.call(this,name)
    }
    // 利用原型继承超类型原型上的方法
    Cat.prototype = Animal.prototype
    
    let c4 = new Cat('狸猫')
    c4.sing() // 我是狸猫,我会唱歌

(4)组合派生继承

      function Animal(name) {
        this.name = name;
      }
      Animal.prototype.eat = function () {
        console.log("哇呜,吃..", this.name);
      };
      // 【重点3】修改原型的[类型描述]
      Animal.prototype[Symbol.toStringTag] = Animal.name;
      
      function Cat(name) {
        Animal.call(this, name);
      }
      // 【重点1 派生】:解决公共原型被修改影响所有实例的问题
      console.log('==========',Cat.prototype)  // Object
      Cat.prototype = Object.create(Animal.prototype);
      console.log('==========',Cat.prototype) // Cat
      
      // 【重点2】掰回歪曲的构造函数
      console.log('----------',Cat.prototype.constructor) // Animal
      Cat.prototype.constructor = Cat;
      console.log('----------',Cat.prototype.constructor) // Cat

      // 【重点3】修改原型的[类型描述]
      Cat.prototype[Symbol.toStringTag] = Cat.name;

      // 测试
      var dogPrototype = Object.create(Animal.prototype);
      console.log(Cat.prototype === dogPrototype); // false

      var c5 = new Cat("布偶");
      c5.eat();

(5)class 继承

    class Duck{
      constructor(legsNumber){
        this.kind = "鸡"
        this.legsNumber = legsNumber
      }
      // 此处的 run 也会被继承 
      run(){
         console.log('跑的飞快!')
      } 
    }
    // extends 关键词
    class Chicken extends Duck{
      kind = "鸡"
      constructor(name) {
        super(2)
        this.name = name
      }
      rap(){
        console.log(`鸡你太美~ 我是${this.name},是只${this.kind},我有${this.legsNumber}条腿。`)
      }
    }
    const c = new Chicken('坤坤')
    c.rap()
    c.run()
    console.dir(c)