es 5の部分継承及びes 6のクラス

5648 ワード

一、JavaScriptでよく使われる原型の継承方式
  • プロトタイプチェーンは
  • を継承します.
    2,コンストラクタ継承(対象と偽って相続する)
    3、コンビネーション継承(プロトタイプチェーン継承+コンストラクター継承)
    プロトタイプチェーン引継ぎ
    function Show(){
    this.name="run";
    }
    
    function Run(){
    this.age="20"; //Run   Show,    ,    
    }
    Run.prototype=new Show();
    var show=new Run();
    alert(show.name)//  :run
    
    コンストラクタ継承(対象を相続と偽る)
    引用共有と超類型では伝わらない問題を解決するために、構造関数を借りるという技術を使って、あるいは対象としてなりすまし(偽造の対象、古典的継承)の技術を使ってこの二つの問題を解決します.
    function Box(age){
        this.name=['Lee','Jack','Hello']
        this.age=age;
    }
    function Desk(age){
        Box.call(this,age); 
    }
    var desk = new Desk(200);
    alert(desk.age);//200
    alert(desk.name);//['Lee','Jack','Hello']
    desk.name.push('AAA'); //      ,   desk
    alert(desk.name)//['Lee','Jack','Hello','AAA']
    
    コンビネーション継承(プロトタイプチェーン継承+構造関数継承)
    構造関数を使って先ほどの二つの問題を解決しましたが、プロトタイプがないと多重化は話せません.したがって,プロトタイプ鎖+構造関数を借用するモードが必要であり,このモードは結合継承になる.
    function Box(age) {
        this.name = ['Lee', 'Jack', 'Hello']
        this.age = age;
    }
    Box.prototype.run = function () {
        return this.name + this.age;
    };
    function Desk(age) {
        Box.call(this, age); //    
    }
    Desk.prototype = new Box(); //     
    var desk = new Desk(100);
    alert(desk.run());
    
    二、クラスの使用
    ES 6のクラスは文法飴だけと見なしてもいいです.ほとんどの機能はES 5でできます.新しいクラスの書き方は対象の原型の書き方をはっきりさせ、対象に向けてプログラミングする文法のようにしか見えません.クラスとモジュール内部では厳格なモードを使用しています.
    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    }
    
    クラスの定義にはconstructor方法が必要です.これは構造方法です.例のオブジェクトを指します.方法を定義する時、カンマ区切りは必要なく、エラーを報告します.
    クラスのデータの種類は関数で、その指向はコンストラクタです.だから、使用する時とコンストラクタは同じで、newキーワードが必要です.
    class Bar {
      doStuff() {
        console.log('stuff');
      }
    }
    
    var b = new Bar();
    b.doStuff() // "stuff"
    
    es 6のクラスにはプロタイプもあります.
    class Point {
      constructor() {}
    
      toString() {}
    
      toValue() {}
    }
    
    //    
    
    Point.prototype = {
      constructor() {},
      toString() {},
      toValue() {},
    };
    
    let b = new Point();
    //      
    b.constructor === B.prototype.constructor // true
    
    Object.assignはprototypeを同時に複数の方法に結びつけることができます.
    class Point {
      constructor(){}
    }
    
    Object.assign(Point.prototype, {
      toString(){},
      toValue(){}
    });
    
    prototype対象のconstructor属性は、直接「クラス」の自身を指すもので、ES 5の行動と一致しています.
    Point.prototype.constructor === Point // true
    
    クラスの内部で定義されているすべての方法は、列挙されません.
    class Point {
      constructor(x, y) {}
    
      toString() {}
    }
    
    Object.keys(Point.prototype)
    // []
    Object.getOwnPropertyNames(Point.prototype)
    // ["constructor","toString"]
    
    上記のコードでは、toStringメソッドはPointクラスの内部定義の方法であり、列挙することができない.この点はES 5の挙動と一致しない.
    var Point = function (x, y) {}
    
    Point.prototype.toString = function() {};
    
    Object.keys(Point.prototype)
    // ["toString"]
    Object.getOwnPropertyNames(Point.prototype)
    // ["constructor","toString"]
    
    上のコードはES 5の書き方をしています.toString方法は列挙可能です.
    クラスはnewで呼び出さなければなりません.そうでないとエラーが発生します.これは普通のコンストラクタとの主な違いです.後者はnewを使わなくても実行できます.
    クラスのインスタンスオブジェクトの書き方は、ES 5と全く同じで、newコマンドを使用しています.前に述べましたが、newを忘れたら、関数のようにクラスを呼び出すと、エラーが発生します.また、クラスの原型の書き方もes 5とあまり違いません.
    class Point {
    
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    
    }
    
    var point = Point(2, 3);//  
    var point = new Point(2, 3);
    
    point.toString() // (2, 3)
    
    point.hasOwnProperty('x') // true
    point.hasOwnProperty('y') // true
    point.hasOwnProperty('toString') // false
    point.__proto__.hasOwnProperty('toString') // true
    
    クラス表式を採用して、すぐに実行するクラスを書くことができます.
    let person = new class {
          constructor(name) {
            this.name = name;
          }
        
          sayName() {
            console.log(this.name);
          }
        }('  ')
    
    Classの取得関数とデポジット関数(setter)
    class CustomHTMLElement {
      constructor(element) {
        this.element = element;
      }
    
      get html() {
        return this.element.innerHTML;
      }
    
      set html(value) {
        this.element.innerHTML = value;
      }
    }
    
    var descriptor = Object.getOwnPropertyDescriptor(
      CustomHTMLElement.prototype, "html"
    );
    
    "get" in descriptor  // true
    "set" in descriptor  // true
         ,             html         ,   ES5     。
    
    class静的方法staticのキーワードはインスタンスに引き継がれませんが、布団類は引き継がれます.
    class Foo {
      static classMethod() {
        return 'hello';
      }
    }
    
    Foo.classMethod() // 'hello'
    
    var foo = new Foo();
    foo.classMethod()// TypeError: foo.classMethod is not a function
    
    class Bar extends Foo {}
    
    Bar.classMethod() // 'hello'
    //       
    class Bar extends Foo {
      static classMethod() {
        return super.classMethod() + ', too';
      }
    }
    
    Bar.classMethod() // "hello, too"
    
    new.target属性newは、構造関数からインスタンスを生成するコマンドである.ES 6はnew命令のためにnew.target属性を導入しています.この属性は一般的に構造関数の中で使用され、newコマンドが作用するその構造関数を返します.構造関数がnewコマンドで呼び出されていない場合、new.targetはundefinedに戻りますので、この属性を用いて構造関数の呼び出しを決定することができます.
    プライベート方法は一般的な需要ですが、ES 6は提供されません.
    命名に区別をつける
    class Widget {
    
      //     
      foo (baz) {
        this._bar(baz);
      }
    
      //     
      _bar(baz) {
        return this.snaf = baz;
      }
    }
    
    プライベート方法と同様に、ES 6はプライベート属性をサポートしていません.現在、クラスに私有属性を加えた提案があります.方法は属性名の前に、〓を使って表します.
    class Point {
      #x;
    
      constructor(x = 0) {
        #x = +x; //    this.#x   
      }
    
      get x() { return #x }
      set x(value) { #x = +value }
    }