继承以及Super

Posted itgezhu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了继承以及Super相关的知识,希望对你有一定的参考价值。

一个小小的总结,主要关注以下三个问题:ES5的继承方式,ES5的继承与ES6的继承的区别,ES6的super的几种使用方式以及其中this的指向。

From http://supermaryy.com

一、ES5的继承

JS实现继承的几种方式

MDN | Object.create | 用 Object.create 实现类式继承

继承可以分为对象实例的继承,类的继承

二、ES6的继承

Class B extends A 中的A可以是个class,还可以是个有prototype属性的函数

三、ES5继承与ES6继承的区别

  1. this的区别

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

  2. 原型链ES6有两条

    class A  
    class B extends A  
    
    B.__proto__ === A // true
    B.prototype.__proto__ === A.prototype // true

    这样的结果是因为,类的继承是按照下面的模式实现的。

    class A  
    class B  
    // B 的实例继承 A 的实例
    Object.setPrototypeOf(B.prototype, A.prototype);
    // B 继承 A 的静态属性
    Object.setPrototypeOf(B, A);
    const b = new B();
    
    //setPrototypeOf的内部实现
    Object.setPrototypeOf = function (obj, proto) 
      obj.__proto__ = proto;
      return obj;
    
    //但是setPrototypeOf会有性能问题,通常推荐使用Object.create
  3. ES6可以继承原生构造函数,而ES5不能

    1. 原生构造函数有:Boolean()、Number()、String()、Array()、Date()、Function()、RegExp()、Error()、Object()
    2. 原因:

      • ES5 是先新建子类的实例对象 this ,再将父类的属性添加到子类上,由于父类的内部属性无法获取,导致无法继承原生的构造函数。

      • ES6 允许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象 this ,然后再用子类的构造函数修饰 this ,使得父类的所有行为都可以继承。

    3. 继承 Object 的子类,有一个 行为差异 。

      class NewObj extends Object
        constructor()
       super(...arguments);
        
      
      var o = new NewObj(attr: true);
      o.attr === true  // false

      上面代码中, NewObj 继承了 Object ,但是无法通过 super 方法向父类 Object 传参。这是因为 ES6 改变了 Object 构造函数的行为,一旦发现 Object 方法不是通过 new Object() 这种形式调用,ES6 规定 Object 构造函数会忽略参数。

四、ES6的super及其this

  1. 作为函数:在子类构造函数中调用 super() ,super相当于父类constructor

  2. 作为对象:

    • 在子类 构造函数或普通函数 中使用 super.methodA() ,super相当于父类原型

      此时methodA中的this指向子类实例

    • 在子类 静态方法 中使用 super.methodB() ,super指向父类而非原型,此时的methodB指的是父类的静态方法methodB

      此时methodB中的this指向子类,所以只能通过this访问到子类的静态方法和属性

  3. 在子类中使用super 给属性赋值 super.father_prop = 1 ,相当于子类的this this.father_prop=1

    class A 
      constructor() 
        this.x = 1;
      
    
    
    class B extends A 
      constructor() 
        super();
        this.x = 2;
        super.x = 3;
        console.log(super.x); // undefined
        console.log(this.x); // 3
      
        change()
            super.x = 4
            console.log(super.x); //undefined
            console.log(this.x);  // 4
        
    
    let b = new B();
    b.change()
  4. 使用 super 的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。

    class A 
    
    class B extends A 
      constructor() 
        super();
        console.log(super); // 报错
      
    

以上是关于继承以及Super的主要内容,如果未能解决你的问题,请参考以下文章

各修饰符作用范围,this()以及super()

python语言中多继承中super调用所有父类的方法以及要用到的MRO顺序

React中super(props)和super()以及不写super()的区别

java学习中,面向对象的三大特性:封装继承多态 以及 super关键字和方法的重写(java 学习中的小记录)

Python进阶-继承中的MRO与super

多重继承如何与 super() 和不同的 __init__() 参数一起工作?