第二十章Classの継承

6210 ワード

概要


  Classはextendsキーワードによって継承を実現することができ、これはES 5がプロトタイプチェーンを修正することによって継承を実現するよりも明確で便利である.
    class Point {
        // ...
    }
    class ColorPoint extends Point {
        constructor (x, y, color) {
            super(x, y)           //  Constructor(x, y)
            this.color = color
        }
        toString () {
            return this.color + '' + super.toString()   //  toString()
        }
    }

上のコードにsuperキーワードが表示されます.親の構造関数を表し、親のthisオブジェクトを新規作成します.  サブクラスはconstructorメソッドでsuperメソッドを呼び出す必要があります.そうしないと、インスタンスを新規作成するときにエラーが表示されます.これは,子クラスが自分のthisオブジェクトを持たず,親クラスのthisオブジェクトを継承して加工するためである.superメソッドを呼び出さないと、サブクラスはthisオブジェクトを取得できません.
class Point {}
class ColorPoint extends Point {
    constructor () {}
}
let cp = new ColorPoint()   //  

 ES 5の継承は、本質的には、サブクラスのインスタンスオブジェクトthisを作成してから、親クラスのメソッドをthisに追加することである(Parent.apply(this))ES 6の継承メカニズムはまったく異なり、実質的に親クラスのインスタンスオブジェクトthisを作成し、子クラスのthisはまだしばらくないので、superメソッドを呼び出してから、子クラスの構造関数でthisを変更する必要があります.
// ES5 
let a = new ColorPoint()
function Point () {}
a.prototype = new Point()

 サブクラスがconstructorメソッドを定義していない場合、このメソッドはデフォルトで追加されます.定義が表示されているかどうかにかかわらず、どのサブクラスにもconstructorメソッドがあります.
    class ColorPoint extends Point {}
    //  
    class ColorPoint extends Point {
        constructor (...args) {
            super(...args)
        }
    }

  もう1つ注意しなければならないのは、サブクラスのコンストラクション関数でsuperを呼び出した後にのみthisキーワードを使用できます.そうしないと、エラーが発生します.これは、サブクラスインスタンスの構築が親インスタンスの加工に基づいているため、superメソッドのみが親インスタンスを返すことができます.
    class Point {
        // ...
    }
    class ColorPoint extends Point {
        constructor (x, y, color) {
            super(x, y)           //  Constructor(x, y)
            this.color = color
        }
    }
    let cp = new ColorPoint(25, 8, 'green')
    cp instanceof ColorPoint   // true
    cp instanceof Point        // true

  上のコードでは、インスタンスオブジェクトcpはColorPointとPointの2つのクラスのインスタンスであり、ES 5の動作と完全に一致する. super(x, y) new Point(x, y)

Object.getPrototypeOf()


  Object.getPrototypeOfメソッドは、子クラスから親クラスを取得するために使用できます.Object.getPrototypeOf(ColorPoint)==Point//trueなので、この方法でクラスが別のクラスを継承しているかどうかを判断できます.

superキーワード


 superキーワードは関数としてもオブジェクトとしても使用できます.この2つの場合、その使い方は全く違います.   ,super 。ES6 , super 。  superは、親Aのコンストラクション関数を表すが、サブクラスBの例、すなわちsuper内部のthisはBを指すので、super()はここではA.prototypeに相当する.constructor.call(this).
    class A {
        constructor () {
            console.log(new.target.name)
        }
    }
    class B extends A {
        constructor () {
            super()
        }
    }
    new A()  // A
    new B()  // B

上のコードではnew.targetは、現在実行中の関数を指します.super()が実行されると、親Aのコンストラクタではなく、サブクラスBのコンストラクタを指すことがわかります.すなわち,super()内部のthisはBを指す.  を関数とする場合,super()はサブクラスのコンストラクション関数のみであり,他の場所で使用するとエラーが報告される.
    class A {}
    class B extends A {
        m () {
            super()   //  
        }
    }

  上のコードではsuper()をBクラスのmメソッドに使用すると文法エラーが発生します.   ,super ; 。
    class A {
        p () {
            return 2
        }
    }
    class B extends A {
        constructor () {
            super()
            console.log(super.p())  // 2
        }
    }
    let b = new B()

  上のコードのうち、サブクラスBのsuper.p()はsuperをオブジェクトとして使用する.このとき、superは一般的な方法の中でA.prototypeを指すので、super.p()はA.prototypeに相当する.p(). super , super 。
    class A {
        constructor () {
            this.p = 2
        }
    }
    class B extends A {
        get m () {
            return super.p
        }
    }
    let b = new B()
    b.m // undefined

上のコードでは、pは親Aのインスタンスの属性であるためsuper.pは参照できません. ES 6では、superによって親クラスを呼び出すメソッドの場合、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.print()呼び出し時A.prototype.だがA.prototype.print()はサブクラスBのthisをバインドし、1ではなく2の出力をもたらします.つまり、実際に実行する場合super.print.call(this).   サブクラスの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()

  上のコードでsuper.xは3に割り当てられ、thisに等しい.xは3に割り当てられます.superを読み込むとxの場合、読み出しに相当するのはA.prototypeである.xなのでundefinedを返します. superがオブジェクトとして静的メソッドで使用される場合、superは親のプロトタイプオブジェクトではなく親を指します.まとめ:superは関数呼び出し時に親を表すコンストラクション関数,すなわちsuperはPointコンストラクション関数,super()は親を呼び出すコンストラクション関数を表し,コンストラクション関数の呼び出しはnew,すなわちnew Point()を用いる必要があり,superメソッドが親インスタンスを返すことができることも説明した.super()はここでA.prototypeに相当する.constructor.call(this).superがオブジェクトである場合、通常の方法で親のプロトタイプオブジェクトを指す.静的メソッドで親を指します.質問:super()はいったい何を表していますか.どうしてsuperが必要なのか、サブクラスにthisがないのはどういう意味ですか.thisの指向はどういうことですか.注意:通常のコンストラクション関数が実行されると、空のオブジェクトがthisとして作成され、実行が続行されますが、派生するコンストラクション関数が実行されると、上記とは異なり、親コンストラクション関数がこの作業を完了することを期待します.したがって、私たちが独自のコンストラクション関数を構築している場合は、superを呼び出さなければなりません.そうしないと、thisを持つオブジェクトは作成されず、エラーが報告されません.
子クラスは自分のthisオブジェクトではなく、親のthisオブジェクトを継承します.superメソッドを呼び出さないと、サブクラスはthisオブジェクトを取得できません.親クラスのthisオブジェクトを取得すると、このthisオブジェクトは子クラスのインスタンスを指します.1つ目のケースsuperは、関数呼び出し時に親を表す構造関数として機能します.superは親クラスのコンストラクション関数を表すが、呼び出すときに返される時の子クラスの例は、super内部のthisがBを指すため、super()はここでA.prototypeに相当する.constructor.call(this).2つ目のケースsuperがオブジェクトとして使用される場合、通常のメソッドでは親のプロトタイプオブジェクトを指し、静的メソッドでは親を指します.

クラスのprototypeプロパティとprotoプロパティ

  • サブクラスのprotoプロパティは、構造関数の継承を表し、常に親を指します.
  • サブクラスのprototype属性のproto属性はメソッドの継承を表し、常に親クラスのprototype属性を指す.
  • class A {}
    class B extends A {}
    B.__proto__ === A // true
    B.prototype.__proto__ === A.prototype  // true