# 继承
# 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)
}
- 原型式继承
 
优点一:仅仅将传入对象作为原型,用来共享属性,方便
问题一:小心引用类型 问题二:全部是 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)
}
- 寄生式继承 本质是根据传入对象,新建、拓展对象 问题:无法实现复用
 
function createAnother(original) {
  let clone = object(original)
  clone.sayHi = function() {
    console.log('hi')
  }
  return clone
}
- 寄生组合式继承 通过构造函数来继承属性,通过原型链混成形式来继承方法。 解决组合式继承,需要第二次调用超类型构造函数问题。
 
{   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这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。
第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。 super虽然代表了父类A的构造函数,但是返回的是子类B的实例 类似:
A.prototype.constructor.call(this)第二种情况,super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。 ES6 规定,在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。