# 继承

# 1. 原型链

问题一:当继承的原型中,包含引用类型时,公用属性将被修改 问题二:创建子类时,不能向超类型的构造函数中传参数

{
  function SuperType() {
    this.name = 'Super'
  }

  SuperType.prototype.getSuperName = function() {
    return this.name
  }

  function SubType() {
    this.subName = 'Sub'
  }

  SubType.prototype = new SuperType()
  SubType.prototype.getSubName = function() {
    return this.subName
  }

  // 实例化,继承之前两者所有属性
  let instance = new SubType()

  console.log(instance.name)
  console.log(instance.getSuperName())

  console.log(instance.subName)
  console.log(instance.getSubName())

  console.log(Object.getPrototypeOf(instance)) // SuperType 的实例 + 拓展方法
  console.log(instance.constructor === SuperType) // true

  boboLog.hr = '判断原型与实例的关系'
  // 只要迭代中 Object.getPrototypeOf(instance) == SubType.prototype
  console.log(instance instanceof SubType)
  console.log(instance instanceof SuperType)
  console.log(instance instanceof Object)
}

# 2. 借用构造函数

问题一:属性方法无法复用,无法继承原型中的方法。

{
  function SuperType(name) {
    this.name = name
    this.sayName = function() {
      console.log(this.name)
    }
  }

  function SubType() {
    SuperType.call(this, 'John')

    this.age = 29
  }

  let instance = new SubType()

  console.log(instance.name)
  console.log(instance.age)
  instance.sayName()
}

# 3. 组合继承

问题一:子元素的原型中,包含超类型构造函数的重复属性 问题二:每次设定子元素原型时,需要注意设定 constructor

{
  function SuperType(name) {
    this.name = name
    this.colors = ['red', 'green', 'yellow']
  }

  SuperType.prototype.sayName = function() {
    console.log(this.name)
  }

  function SubType(name, age) {
    SuperType.call(this, name)
    this.age = age
  }

  SubType.prototype = new SuperType()
  SubType.prototype.constructor = SubType
  SubType.prototype.sayAge = function() {
    console.log(this.age)
  }

  let instance1 = new SubType('john', 19)

  instance1.colors.push('black')

  let instance2 = new SubType('Allan', 22)

  console.log(instance1.colors)
  console.log(instance2.colors)
  console.log(Object.getPrototypeOf(instance2).name)
  console.log(Object.getPrototypeOf(instance2).colors)
}
  1. 原型式继承

优点一:仅仅将传入对象作为原型,用来共享属性,方便

问题一:小心引用类型 问题二:全部是 Object 构造器

{
  let person = {
    name: 'john',
    friends: ['Hao', 'Ming']
  }

  let antherPerson = Object.create(person, {
    name: {
      value: 'Zing'
    }
  })

  let yetPerson = Object.create(antherPerson)

  console.log(antherPerson.name)
  console.log(antherPerson.friends)

  boboLog.hr = '原型链,继承父所有属性'
  console.log(yetPerson.name)
  console.log(yetPerson.friends)
}
  1. 寄生式继承 本质是根据传入对象,新建、拓展对象 问题:无法实现复用
function createAnother(original) {
  let clone = object(original)

  clone.sayHi = function() {
    console.log('hi')
  }

  return clone
}
  1. 寄生组合式继承 通过构造函数来继承属性,通过原型链混成形式来继承方法。 解决组合式继承,需要第二次调用超类型构造函数问题。
{   function inheritPrototype(subType, superType) {
      let prototype = Object.create(superType.prototype) // 复制,原型指向指向超类型原型

      prototype.constructor = subType
      subType.prototype = prototype
    }


    function SuperType(name) {
      this.name = name
      this.colors = ['red', 'blue']
    }

    SuperType.prototype.sayName = function() {
      console.log(this.name)
    }

    SuperType.prototype.books = ['1', '2']

    // 完成实例属性的继承
    function SubType(name, age) {
      SuperType.call(this, name)

      this.age = age
    }

    inheritPrototype(SubType, SuperType)

    SubType.prototype.sayAge = function() {
      console.log(this.age)
    }

    // 测试
    let instance = new SubType('Ming', 19)

    console.log(SuperType.prototype)
    console.log(SubType.prototype)

    boboLog.hr = '查看构造函数'
    console.log(SuperType.prototype.constructor)
    console.log(SubType.prototype.constructor)
    instance.books.push(3)

    console.log(instance.books)

    let instance2 = new SuperType('Wang')
    console.log(instance2.books)
}

# es6

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。如果不调用super方法,子类就得不到this对象。

class Son extends Parent {
  constructor(x, y, z) {
    super(x, y)
    this.z = z
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。 ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

  1. 第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。 super虽然代表了父类A的构造函数,但是返回的是子类B的实例 类似:A.prototype.constructor.call(this)

  2. 第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。 ES6 规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。

Last Updated: 5/14/2022, 11:38:45 AM