继承 8种方式

原型链继承

  • 重点:子的原型对象为new一个父的实例Child.prototype = new Parent();
  • 缺点:多个实例对引用类型的操作会被篡改

    借用构造函数继承

  • 重点:在子构造函数内部调用父构造函数Parent.call(this)

  • 缺点:无法实现复用,不能继承原型属性/方法

    组合继承

  • 重点:使用原型链继承共享的属性和方法,通过借用构造函数继承实例属性

    1. function Child(name,age){
    2. // 继承属性
    3. Parent.call(this, name)
    4. this.age=age
    5. }
    6. // 继承方法
    7. Child.prototype = new Parent()
    8. Child.prototype.constructor = Child;
  • 缺点:无论在什么情况都会调用两次父构造函数,一次是创建子类型原型,另一次是在子构造函数内部

    原型式继承

  • 重点:执行对给定对象的浅复制

    1. function object(obj){
    2. function F(){}
    3. F.prototype=obj
    4. return new F();
    5. }
    6. var person1=object(person);

    在ES5中Object.create()可替换上面的方法object()var person1 = Object.create(person);

  • 缺点:原型链继承多个实例的引用类型属性指向相同,存在篡改的可能;无法传递参数

    寄生式继承

  • 重点:在原型式继承的基础上,增强对象,返回构造函数

    1. function createAnother(obj){
    2. var clone=object(obj);
    3. // ES5中用这个
    4. // var clone=Object.create(obj);
    5. // 增强对象
    6. clone.sayHi=function(){};
    7. return clone;
    8. }
    9. var person1=createAnother(person)
  • 缺点:同原型式继承

    寄生组合式继承

  • 重点:结合构造函数传递参数和寄生模式实现继承

    1. // 借用构造函数增强子类实例属性(支持传参和避免篡改)
    2. function Child(name,age){
    3. // 继承属性
    4. Parent.call(this, name)
    5. this.age=age
    6. }
    7. function inheritPrototype(Child, Parent){
    8. var prototype=Object.create(Parent.prototype);
    9. prototype.constructor=Child;
    10. Child.prototype=prototype;
    11. }
    12. // 将父类原型指向子类,这样子类就能使用父类原型链的属性/方法
    13. inheritPrototype(Child, Parent);

    优点:只调用一次构造函数,原型链不变,是最成熟的

    混入方式继承多个方式

    重点:利用Object.assign将父类原型上的方法拷贝到子类原型上,这样子类实例实例就可以使用父类的方法

    1. Object.assign(Child.prototype, Parent.prototype);
    2. Child.prototype.constructor=Child;

    ES6类 extends

    重点:使用extends表明继承自哪个父类,并且在子类构造函数中必须使用super,可以看做是Parent.call(this,value)

    1. class Parent{
    2. constructor(value){
    3. this.val=value
    4. }
    5. }
    6. class Child extends Parent{
    7. constructor(value){
    8. super(value)
    9. this.val = value
    10. }
    11. }