【ES 6】継承しやすいクラス構文


他のオブジェクト向けプログラミング言語と同様に、ES 6はclassクラスおよびextend継承構文糖を正式に定義し、静的、派生的、抽象的、反復的、単例などをサポートし、ES 6の新しい特性に基づいて多くの興味深い用法を派生させる.

一、クラスの基本定義


基本的にすべてのオブジェクト向け言語はクラスのカプセル化と継承をサポートしています.それはクラスとは何ですか.
クラスは、データパッケージ、データ操作、およびメッセージを伝達する関数を含むオブジェクト向けプログラム設計の基礎です.クラスのインスタンスをオブジェクトと呼びます.
ES 5の前に関数によってクラスをシミュレートした実装は以下の通りである.
//     
function Person(name) {
  this.name = name;
}
//       
Person.prototype.sayName = function(){
  console.log(this.name);
};
// new     
var friend = new Person("Jenny");

friend.sayName(); // Jenny
console.log(friend instanceof Person);   // true
console.log(friend instanceof Object);   // true

要約すると、クラスを定義する考え方は以下の通りです.
  • 1.コンストラクション関数パッケージデータ
  • が必要
  • 2.プロトタイプにメソッド操作データを追加する
  • 3.Newによるインスタンス
  • の作成
    ES 6は、classのキーワードを使用してクラスを定義します.このクラスには、特別なメソッド名[[Construct]]が構造関数を定義し、newがインスタンスを作成するときに呼び出されるのは[[Construct]]です.例は次のとおりです.
    /*ES6*/
    //     let Person = class {
    class Person {
      //     
      constructor(name) {
        this.name = name;
      }
      //    Person.prototype.sayName
      sayName() {
        console.log(this.name);
      }
    }
    
    console.log(typeof Person);   // function
    console.log(typeof Person.prototype.sayName);   // function
    
    let friend = new Person("Jenny");
    
    friend.sayName(); // Jenny
    console.log(friend instanceof Person);   // true
    console.log(friend instanceof Object);   // true

    上記の例ではclassで定義されたクラスとカスタム関数シミュレーションクラスの機能には違いはないようですが、本質的には大きな違いがあります.
  • 関数宣言は昇格可能であるが、classクラス宣言はletと類似しており、昇格できない.
  • クラス宣言は、厳格なモードで自動的に実行され、「use strict」である.
  • クラスのすべての方法は枚挙にいとまがない.enumerableはfalseである.

  • 二、より柔軟なクラス


    クラスは関数と同様に、JavaScriptの一等公民(関数を転送したり、関数から返したり、値を付与したりすることができます)であり、クラスとオブジェクトの字面量にはより多くの類似点があることに気づき、これらの特徴はクラスのより柔軟な定義と使用を拡張することができます.

    2.1アクセサ属性を持つ


    オブジェクトの属性にはデータ属性とアクセス属性があり、クラスではgetsetのキーワードでアクセサ属性を定義することもできます.
    class Person {
      constructor(name) {
        this.name = name;
      }
    
      get value () {
        return this.name + this.age
      }
      set value (num) {
        this.age = num
      }
    }
    
    let friend = new Person("Jenny");
    //      setter
    friend.value = 18
    //      getter
    console.log(friend.value) // Jenny18

    2.2計算可能なメンバー名


    ES 6オブジェクトの字面量拡張のような計算可能な属性名は、クラス内のメソッドおよびアクセサ属性を含む計算可能なメンバー名を[式]で定義することもできます.
    let methodName = 'sayName'
    
    class Person {
      constructor(name) {
        this.name = name;
      }
    
      [methodName + 'Default']() {
        console.log(this.name);
      }
    
      get [methodName]() {
        return this.name
      }
    
      set [methodName](str) {
        this.name = str
      }
    }
    
    let friend = new Person("Jenny");
    
    //   
    friend.sayNameDefault(); // Jenny
    //      
    friend.sayName = 'lee'
    console.log(friend.sayName) // lee

    オブジェクトの新しい特性をさらに熟知したい場合は、「ES 6」オブジェクトの新しい機能と解構賦値を参照してください.

    2.3デフォルト反復器の定義


    ES 6でよく使用される集合オブジェクト(配列、Set/Map集合)および文字列は反復可能なオブジェクトであり、クラスがこれらの反復可能なオブジェクトの値を表すために使用される場合、デフォルトの反復器を定義するとより便利です.
    ES 6は、Symbol.iterator属性にジェネレータを追加することによって、デフォルトの反復器を定義する.
    class Person {
      constructor(name) {
        this.name = name;
      }
    
      *[Symbol.iterator]() {
        for (let item of this.name){
          yield item
        }
      }
    }
    
    var abbrName = new Person(new Set(['j', 'j', 'e', 'e', 'n', 'y', 'y', 'y',]))
    for (let x of abbrName) {
      console.log(x); // j e n y
    }
    console.log(...abbrName) // j e n y

    デフォルトの反復器を定義したクラスのインスタンスでは、for-ofループと展開演算子(...)を使用できます.などの反復機能があります.
    以上の反復器の内容に困惑する参考:【ES 6】反復器と反復可能オブジェクト

    2.4パラメータとしてのクラス


    クラスは「一等公民」として、パラメータが入力関数を使用する場合に使用できます.もちろん、関数から返すこともできます.
    function createClass(className, val) {
      return new className(val)
    }
    
    let person = createClass(Person,'Jenny')
    console.log(person) // Person { name: 'Jenny' }
    console.log(typeof person) // object

    2.5単一インスタンスの作成


    クラス構文を使用して単一のインスタンスを作成するには、newを使用してクラス式をすぐに呼び出します.
    let singleton = new class {
      constructor(name) {
        this.name = name;
      }
    }('Jenny')
     
    console.log(singleton.name) // Jenny

    ここで匿名クラス式を作成し、newがクラス式を呼び出し、カッコですぐに実行します.このクラス構文で作成された単一の例は、役割ドメインでクラスの参照を露出しません.

    三、クラスの継承


    ES 6を振り返る前にどのように継承を実現しますか?一般的な方法は、プロトタイプチェーン、構造関数、および組合せ継承などの方法です.
    ES 6のクラスは、よく知られているextendsのキーワードを使用してクラス継承関数を指定し、surpe()の方法で親クラスの構築関数にアクセスすることができる.
    たとえばPersonのクラスを継承します.
    class Friend extends Person {
      constructor(name, phone){
        super(name)
        this.phone = phone
      }
    }
    
    let myfriend = new Friend('lee',2233)
    console.log(myfriend) // Friend { name: 'lee', phone: 2233 }

    FriendはPersonを継承し,用語ではPersonをベースクラス,Friendを派生クラスと呼ぶ.
    なお、surpe()は派生クラスでのみ使用でき、thisの初期化を担当するため、派生クラスがthisを使用する前にsurpe()を使用する必要があります.

    3.1建設対象の継承


    ES 6のクラス継承は、組み込みオブジェクト(Array、Set、Mapなど)を継承することができ、継承後はベースクラスのすべての組み込み機能を持つことができる.例:
    class MyArray extends Array {
    }
    
    let arr = new MyArray(1, 2, 3, 4),
      subarr = arr.slice(1, 3)
    
    console.log(arr.length) // 4
    console.log(arr instanceof MyArray) // true
    console.log(arr instanceof Array) // true
    console.log(subarr instanceof MyArray) // true

    前述の例では、arrは派生クラスMyArrayのインスタンスであるだけでなく、subarrも派生クラスMyArrayのインスタンスであり、組み込みオブジェクト継承の実用的な点は、戻りオブジェクトのタイプを変更することである.
    ブラウザエンジンの背後には[Symbol.species]プロパティは、関数の静的アクセサプロパティを返すために使用され、組み込みオブジェクトが定義されています.[Symbol.species]属性は、Array、ArrayBuffer、Set、Map、Promise、RegExp、Type arraysである.

    3.2式を継承するクラス


    現在、extendsはクラスと組み込みオブジェクトを継承できますが、より強力な機能は式からクラスをエクスポートします.
    この式の要件は、関数として解析され、[[Construct]]の属性とプロトタイプを有することができ、例は以下の通りである.
    function Sup(val) {
      this.value = val
    }
    
    Sup.prototype.getVal = function () {
      return 'hello' + this.value
    }
    
    class Derived extends Sup {
      constructor(val) {
        super(val)
      }
    }
    
    let der = new Derived('world')
    console.log(der) // Derived { value: 'world' }
    console.log(der.getVal()) // helloworld

    3.3継承できる抽象クラス


    ES 6は、new.targetメタ属性判定関数がnewキーワードによって呼び出されたか否かを導入する.クラスの構築関数は、new.targetによってクラスがどのように呼び出されたかを決定することもできる.
    抽象クラス(インスタンス化できないクラス)は、new.targetで作成できます.たとえば、次のようになります.
    class Abstract  {
      constructor(){
        if(new.target === Abstract) {
          throw new Error('   (       )')
        }
      }
    }
    
    class Instantiable extends Abstract {
      constructor() {
        super()
      }
    }
    
    // let abs = new Abstract() // Error:    (       )
     let abs = new Instantiable()
    console.log(abs instanceof Abstract) // true

    Abstract抽象クラスを直接使用してインスタンスを作成することはできませんが、ベースクラスとして他のクラスを派生させることができます.

    四、クラスの静的メンバー


    ES 6は、staticキーワードを使用して静的メンバーまたはメソッドを宣言する.クラスのメソッドまたはアクセサ属性の前にstaticを使用できます.唯一の制限は、関数の構築に使用できないことです.
    静的メンバーの役割は、一部のクラスメンバーのプライベート化であり、インスタンスにアクセスできないため、クラスに直接アクセスする必要があります.
    class Person {
      constructor(name) {
        this.name = name;
      }
    
      static create(name) {
        return new Person(name);
      }
    }
    
    let beauty = Person.create("Jenny");
    // beauty.create('lee') // TypeError

    ベースクラスに静的メンバーがある場合、これらの静的メンバーは派生クラスでも使用できます.
    例えば、前例のPersonをベースクラスとしてFriendクラスを派生させ、ベースクラスの静的メソッドcreate()を使用する.
    class Friend extends Person {
      constructor(name){
        super(name)
      }
    }
    
    var friend = Friend.create('lee')
    console.log(friend instanceof Person) // true
    console.log(friend instanceof Friend) // false

    派生クラスは依然としてベースクラスの静的メソッドを使用できることがわかる.
    『ES 6を深く理解する』をお勧めします

    がんばれ少年!