ECMAScript 6(25)class継承

7332 ワード

1.class継承
1.1継承とは
  • は2つのクラスを定義し、1つのクラスには別のクラスの大部分の方法と属性が含まれているので、2つの方法と属性の繰返し度の高いクラスを定義するのは少しもったいない.
  • は、Aクラスのメソッドを継承することによってBに継承する、BはAクラスのメソッドと属性を使用することができ、これが継承である.BはAを継承し、Aは親類、B子類と呼ぶ.
  • es 5はどのように継承を実現するか、2つのコンストラクション関数を定義し、サブクラスでapplyを使用して親クラスを呼び出し、親クラスthisが実装属性の継承を指すことを再定義し、その後、子クラスのprototype=親クラスのprototype実装方法の継承を定義するが、これによりサブクラスのprototypeが書き換えられ、サブクラスがメソッドを追加するにはこのステップの後でなければならない.これもes 5継承の不足点である.
  • es 6はextendsキーワードによって直接実現され、文法はより簡単で直接的である.

  • 1.2 class継承(extends)
    サブクラスextends親
    class Point {
    }
    
    class ColorPoint extends Point {
    }
    

    1.3 constructor
  • classでは、サブクラスがconstructorメソッドを書かない場合、デフォルトでは親constructor
  • が継承されます.
    class ColorPoint extends Point {
    }
    
    //    
    class ColorPoint extends Point {
      constructor(...args) {
        super(...args);
      }
    }
    
  • ただしconstructorメソッドが書かれている場合はsuperメソッドを呼び出す必要があります.そうしないと、インスタンスを新規作成するときにエラーが発生します.
  • 理由:これは、サブクラス独自のthisオブジェクトが、親の構造関数によって作成され、親と同じインスタンス属性と方法が得られ、その後、それを加工し、サブクラス独自のインスタンス属性と方法を加えなければならないためです.superメソッドを呼び出さないと、サブクラスはthisオブジェクトを取得できません.
  • サブクラスのコンストラクション関数では、superを呼び出した後にのみthisキーワードを使用できます.そうしないと、エラーが表示されます.これは、サブクラスインスタンスの構築であり、親インスタンスに基づいてsuperメソッドのみが親インスタンスを呼び出すことができるためです.
  • class ColorPoint extends Point {
      constructor(x, y, color) {
        // this.color = color;      
        super(x, y); //      constructor(x, y)
        this.color = color;
      }
    
      toString() {
        return this.color + ' ' + super.toString(); //      toString()
      }
    }
    
  • ES 5の継承は、本質的にはサブクラスのインスタンスオブジェクトthisを作成してから、親クラスのメソッドをthisに追加します(Parent.apply(this)).ES 6の継承メカニズムはまったく異なり、実質的には親インスタンスオブジェクトの属性とメソッドをthisに追加し(superメソッドを呼び出す必要がある)、次にサブクラスの構造関数でthisを変更する.
  • es 5は、まず子を構築する後に親を継承し、その後改造し、es 6はまず親を継承した後に子を構築し、その後改造
  • .
    1.4親と子の関係
  • es 6は、この2つの条件を満たす
  • を継承する.
  • 親のメソッドと属性布団クラス継承
  • 親の静的メソッドで、布団クラスが継承されます.
  • class A {
        a() {
        }
        static aa(){
          console.log('aa')
        }
    }
    
    class B extends A {
        b() {
        }
    }
    var b = new B()
    //        ,     。
    B.aa() // aa
    b.aa() // Uncaught TypeError: b.aa is not a function
    //     B.__proto__ === A
    //        new      ,     prototype        __proto__        (          ,   __proto__           )
    //         prototype   
    //    B.prototype === A.prototype;  // false
    //     false?     es5     ,          prototype,       (                  )
    //           B.prototype   ,       __proto__  ,  es6    prototype       prototype.__proto__   ,        ,          ,     __proto__       。
    //     B.prototype.__proto__ === A.prototype;  // true
    

    Es 6の2つの条件は、
    B.proto==A//true静的メソッドはB.prototypeを継承する.proto === A.prototype;//trueプロパティメソッド継承
    1.5 Object.getPrototypeOf()
  • Object.getPrototypeOfメソッドは、子クラスから親クラスを取得するために使用できます.
  • Object.getPrototypeOf(B) === A // true
    
  • は、1つのクラスが別のクラスを継承しているかどうかを判断するためにこの方法を使用することができる.

  • 1.6 extendsを使用しないで継承を実現する方法
  • extendsを使用しないで
  • を継承する方法
    function A(){
      ...
    }
    A.staticA = function(){}
    A.prototype.A = function(){}
    
    class B {
        constructor() {
            A.prototype.constructor.call(this) //   
        }
        b() {
            console.log('bar')
        }
    }
    //   :     
    B.__proto__ = A
    B.prototype.__proto__ = A.prototype
    //       
    

    2. super
    superというキーワードは、関数としてもオブジェクトとしても使用できます.この2つの場合、その使い方は全く違います.
  • の第1のケースは、関数として呼び出されると、親の構造関数を表す.
  • は、サブクラスのコンストラクション関数でのみ使用できます.
  • thisより前に
  • を呼び出す
  • 上記の状況を満たさないと
  • を一度実行しなければならない.
    class A {}
    
    class B extends A {
      constructor() {
        super();  // super()      A.prototype.constructor.call(this)。
      }
    }
    
  • 第2の場合、対象とした場合
  • .
  • 一般的な方法では、親のプロトタイプオブジェクトを指します.
  • class A {
      p() {
        return 2;
      }
    }
    
    class B extends A {
      constructor() {
        super();
        console.log(super.p()); // 2
      }
    }
    
    let b = new B();
    
  • 静的メソッドでは、親を指します.
  • class Parent {
      static myMethod(msg) {
        console.log('static', msg);
      }
    
      myMethod(msg) {
        console.log('instance', msg);
      }
    }
    
    class Child extends Parent {
      static myMethod(msg) {
        super.myMethod(msg);
      }
    
      myMethod(msg) {
        super.myMethod(msg);
      }
    }
    
    Child.myMethod(1); // static 1
    
    var child = new Child();
    child.myMethod(2); // instance 2
    
  • superは親のプロトタイプオブジェクトを指すため、親インスタンスに定義されたメソッドまたは属性はsuperで呼び出すことができません.
  • class A {
      constructor() {
        this.p = 2;
      }
    }
    
    class B extends A {
      get m() {
        return super.p;
      }
    }
    
    let b = new B();
    b.m // undefined
    
  • 属性が親クラスのプロトタイプオブジェクトに定義されている場合、superは取得できます.
  • class A {}
    A.prototype.x = 2;
    
    class B extends A {
      constructor() {
        super();
        console.log(super.x) // 2
      }
    }
    
    let b = new B();
    
  • thisはサブクラスインスタンスを指すため、superによって属性に値を割り当てると、superはthisであり、値を割り当てる属性はサブクラスインスタンスの属性になります.
  • 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
      }
    }
    
    let b = new B();
    
  • 6.サブクラスの静的メソッドでsuperによって親クラスを呼び出すメソッドの場合、メソッド内部のthisは現在のサブクラスを指し、
  • class A {
      constructor() {
        this.x = 1;
      }
      static print() {
        console.log(this.x);
      }
    }
    
    class B extends A {
      constructor() {
        super();
        this.x = 2;
      }
      static m() {
        super.print();
      }
    }
    
    B.x = 3;
    B.m() // 3
    
  • superを対象として使用する場合はsuperのみとなる.xxはsuperを直接印刷するのではなく、
  • とエラーが発生します.
    3.class文法糖
  • 実際には
  • について説明しています
  • 各オブジェクトにはprotoプロパティがあり、対応するコンストラクション関数のprototypeプロパティを指します.Classは構造関数の構文糖としてprototype属性とproto属性を同時に持つため,2つの継承鎖が同時に存在する.
  • コンストラクタがnewによってインスタンスを生成すると、コンストラクタのprototype属性は、インスタンスのプロトタイプチェーン
  • としてprotoに自動的に変換される.
  • サブクラスのprotoプロパティは、コンストラクション関数の継承を表し、常に親を指します.
  • サブクラスprototypeプロパティのprotoプロパティは、メソッドの継承を表し、常に親クラスのprototypeプロパティを指します.
  • class A {
    }
    
    class B extends A {
    }
    
    B.__proto__ === A // true
    B.prototype.__proto__ === A.prototype // true
    

    4.原生構造関数の継承
  • Array
  • を継承
    class MyArray extends Array {
      constructor(...args) {
        super(...args);
      }
    }
    
    var arr = new MyArray();
    arr[0] = 12;
    arr.length // 1
    
    arr.length = 0;
    arr[0] // undefined
    
  • 継承Object
  • class NewObj extends Object{
      constructor(){
        super(...arguments);
      }
    }
    var o = new NewObj({attr: true});
    o.attr === true  // false
    

    など...もっと継承してチェン一峰es 6を参考にします
    5. Mixin
  • は、複数のクラス継承を実現する
  • である.
  • チェン一峰の実現
  • function mix(...mixins) {
      class Mix {
        constructor() {
          for (let mixin of mixins) {
            copyProperties(this, new mixin()); //       
          }
        }
      }
    
      for (let mixin of mixins) {
        copyProperties(Mix, mixin); //       
        copyProperties(Mix.prototype, mixin.prototype); //       
      }
    
      return Mix;
    }
    
    function copyProperties(target, source) {
      for (let key of Reflect.ownKeys(source)) {
        if ( key !== 'constructor'
          && key !== 'prototype'
          && key !== 'name'
        ) {
          let desc = Object.getOwnPropertyDescriptor(source, key);
          Object.defineProperty(target, key, desc);
        }
      }
    }
    

    参考博文阮一峰es 6