美文网首页
ES6 浅谈class继承机制

ES6 浅谈class继承机制

作者: 宋乐怡 | 来源:发表于2019-03-21 18:34 被阅读0次

    文章来源阮一峰ES6入门,这里做要点掌握大纲。
    class——构造函数的语法糖
    ES5的继承:修改原型链
    先创造子类的实例对象,再将父类的方法添加到this(Parent.apply(this) )

    ES6的继承:通过extends实现继承
    先将父类实例 的属性方法加到this上(super),然后再用子类的构造函数修改this

    • super
    1. 子类必须在构造函数中调用super方法,用来创建父类的this对象。因为子类this通过父类构造函数塑造,得到和父类一样的实例属性和方法(实例属性和类的本身属性参考上一节class的基本语法。)不调用super,子类就得不到this。
      在子类的构造函数中,只有调用super之后才可以使用this 关键字,因为super 之后子类才有了自己的this。
    2. super关键字可以当函数使用也可以当对象使用。用法不同。必须显示指定super的数据类型
    class A {}
    
    class B extends A {
      constructor() {
        super();
        console.log(super.valueOf() instanceof B); // true,valueOf()返回该对象的原始值。
      }
    }
    
    let b = new B();
    

    作为函数使用时,代表父类的构造函数,只能在子类构造函数中使用,super内部的this指向子类实例。

    class A {
      constructor() {
        console.log(new.target.name);
      }
    }
    class B extends A {
      constructor() {
        super();
      }
    }
    new A() // A
    new B() // B
    
    

    作为对象使用时,在静态方法中指向父类,在普通方法中,指向父类原型对象。
    注意:super指向父类的原型对象,而不是父类实例,所以父类实例上的属性方法无法通过super调用。(父类构造函数里this调用的属性方法就是实例属性方法)

    class A {
      constructor() {
        this.p = 2;
      }
    }
    
    class B extends A {
      get m() {
        return super.p;
      }
    }
    
    let b = new B();
    b.m // undefined
    

    定义在父类实例上的属性应该是这样子

    class A {}
    A.prototype.x = 2;
    
    class B extends A {
      constructor() {
        super();
        console.log(super.x) // 2
      }
    }
    
    let b = new B();
    

    在普通方法中使用super 对象时, 方法内部的this指向当前的子类实例

    class A {
      constructor() {
        this.x = 1;
      }
      print() {
        console.log(this.x);
      }
    }
    
    class B extends A {
      constructor() {
        super();
        this.x = 2;
      }
      m() {
        super.print();
      }
    }
    
    let b = new B();
    b.m() // 2
    

    对象总是继承自另一个对象,所以可以在任意一个对象里使用super

    var obj = {
      toString() {
        return "MyObject: " + super.toString();
      }
    };
    
    obj.toString(); // MyObject: [object Object]
    
    • 子类的构造方法如果没有写也会被自动添加。
    • 子类的实例也是父类的实例
    let cp = new ColorPoint(25, 8, 'green');
    
    cp instanceof ColorPoint // true
    cp instanceof Point // true
    
    • 父类的static 方法会被子类继承
      去class基本语法里会看到静态方法(属性)和私有方法(属性)的使用方法
      静态方法只能直接通过类调用,但不能被实例继承,变量名:static variable
      私有方法只能在类内部使用 ,变量名:#variable
    • 判断一个类是否继承了另一个类
      Object.getPrototypeOf()可以获取子类的父类
    Object.getPrototypeOf(child) === parent
    // true
    
    • 类的prototype属性和proto属性
      大多数浏览器的 ES5 实现之中,每一个对象都有proto属性,指向对应的构造函数的prototype属性。Class 作为构造函数的语法糖,同时有prototype属性和proto属性,因此同时存在两条继承链。

    (1)子类的proto属性,表示构造函数的继承,总是指向父类。

    (2)子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。
    我知道这张图可能不准确,但是这样记能让我一下子找到对应关系。

    image.png
    • 子类原型的原型是父类的原型,emm
    var p1 = new Point(2, 3);
    var p2 = new ColorPoint(2, 3, 'red');
    
    p2.__proto__ === p1.__proto__ // false
    p2.__proto__.__proto__ === p1.__proto__ // true
    
    image.png
    这里有个作用就是通过子类的实例可以修改父类的实例
    子类实例.proto.proto.attr = whatever;,修改父类,进而音箱父类的实例。
    • 原生构造函数的继承
      原生构造函数,是指语言内置的构造函数,用来生成数据结构,ES的构造函数有9种:
      Boolean(),String(),Number(),
      Object(),Array(),Function(),
      Date(),RegExp(),Error(),
      后面的我就不想写了...

    相关文章

      网友评论

          本文标题:ES6 浅谈class继承机制

          本文链接:https://www.haomeiwen.com/subject/bronmqtx.html