『十七』E 6のclass

9041 ワード

ES 6以前はクラスを構造関数でシミュレートしていた.
function Person(name){
	//  
    this.name = name;
}

// 
Person.prototype.showName = function(){
    return ` ${this.name}`;
}
// :
Object.assign(Person.prototype,{
	showName(){
		 return ` ${this.name}`
	}
})

let p1 = new Person(' ');
console.log(p1.showName());

この書き方は、C++やJavaなどの従来のオブジェクト向け言語とは大きく異なります.

class:


ES 6は従来の言語に近い書き方を提供し,class(クラス)の概念を導入した.クラスキーでクラスを定義できます.使用する場合、直接クラスに対してnewコマンドを使用し、コンストラクション関数の使い方と完全に一致します.
基本的に、ES 6のcalssは文法糖と見なすことができ、そのほとんどの機能は、ES 5で行うことができます.新しいclassの書き方は、オブジェクトの原型の書き方をより明確にし、オブジェクト向けにプログラミングする文法に似ているだけです.文法糖:文法糖の役割は、書くコードを簡単にし、理解しやすいようにすることです.
classにはアップグレードはありません.
class Person{
	// ,ES5 Person, ES6 Person 
	constructor(name){
		// 
		this.name = name;//this 
	}
	// , , function ; , 
	showName(){
		 return ` ${this.name}`
	}
}

let p1 = new Person(' ');
console.log(p1.showName());

ESのクラスは,完全に構造関数の別の書き方と見なすことができる.クラスのデータ型は関数であり,クラス自体は構造関数を指す.
console.log(typeof Person)//function
console.log(Person === Person.prototype.constructor)//true

コンストラクション関数のprototypeプロパティは、ES 6のクラス上に引き続き存在します.実際、クラスのすべてのメソッドはprototypeプロパティに定義されています.
class Person{
	constructor(){}
	showName(){}
}

// 
Person.prototype = {
	constructor(){}
	showName(){}
}

class式:
関数と同様に、クラスは式の形式で定義することもできます.
const Person = class {}

属性式:
クラスのプロパティ名は、カッコで囲まれる式を使用できます.
let method = "show";
let str = "Name";
class Person{
	constructor(name){
		this.name = name;
	}
	
	[method+str](){
		 return ` ${this.name}`
	}
}

let p1 = new Person(' ');

console.log(p1.showName());
console.log(p1[method+str]()); 

constructorメソッド:
constructorメソッドはクラスのデフォルトメソッドです.newコマンドでオブジェクトインスタンスを生成すると、このメソッドが自動的に呼び出されます.constructorメソッドは、デフォルトでインスタンスオブジェクト(this)を返します.クラスにはconstructorメソッドが必要です.明示的に定義されていない場合は、空のconstructorメソッドがデフォルトで追加されます.
class Person{}

// 
class Person{
	constructor(){}
}

静的メソッド:
クラスはインスタンスのプロトタイプに相当し、クラスで定義されたすべてのメソッドはインスタンスによって継承されます.
1つのメソッドの前にstaticキーを付けると、そのメソッドはインスタンスで継承されず、クラスで直接呼び出されることを「静的メソッド」と呼びます.
class Foo{
    static print(){
        return 'hello world';
    }
}

Foo.print(); //"hello world"

var foo = new Foo();
foo.print()
// TypeError: foo.printis not a function

静的メソッドにthisキーワードが含まれている場合、このthisはインスタンスではなくクラスを指します.
class Foo {
  static bar() {
    this.baz();
  }
  // 
  static baz() {
    console.log('hello');
  }
  baz() {
    console.log('world');
  }
}

Foo.bar() // hello

静的プロパティ:
静的属性とは、class自体の属性、すなわちclassを指す.インスタンスオブジェクト(this)に定義されている属性ではなく、propName.
class Foo {
}

Foo.prop = 1;
Foo.prop // 1

現在、ES 6はclass内部に静的メソッドしかなく、静的属性がないことを明確に規定しているため、このような書き方だけが可能である.インスタンス属性の前にstaticキーワードを付けることを提案したクラスの静的属性がある.
class MyClass {
  static myStaticProp = 42;

  constructor() {
    console.log(MyClass.myStaticProp); // 42
  }
}

classの継承:


Classはextendsキーワードで継承できます.
サブクラスはconstructorメソッドでsuperメソッドを呼び出さなければなりません.そうしないと、インスタンスを新規作成する際にエラーが発生します.これは、サブクラス独自のthisオブジェクトが、親のコンストラクション関数で作成され、親と同じインスタンス属性とメソッドが得られ、その後、それを加工し、サブクラス独自のインスタンス属性とメソッドを加えなければなりません.superメソッドを呼び出さなければ、サブクラスはthisオブジェクトを得ることはできません.
ES 5の継承は,本質的にはサブクラスのインスタンスオブジェクトthisを作成してから親クラスのメソッドをthisに追加する(Parent.apply(this))ことである.ES 6の継承メカニズムはまったく異なり、実質的には親インスタンスオブジェクトの属性とメソッドをthisに追加し(superメソッドを呼び出す必要がある)、次にサブクラスの構造関数でthisを変更します.
class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); //  constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); //  toString()
  }
}

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

//  
class ColorPoint extends Point {
  constructor(...args) {
    super(...args);
  }
}

親クラスの静的メソッドは、クラスに継承されます.
class A {
  static hello() {
    console.log('hello world');
  }
}

class B extends A {
}

B.hello()  // hello world

superキーワード:
superキーワードは関数としてもオブジェクトとしても使用できます.この2つの場合、その使い方は全く違います.
superを使用する場合は、関数として使用するかオブジェクトとして使用するかを明示的に指定する必要があります.そうしないと、エラーが発生します.
class A {}

class B extends A {
  constructor() {
    super();
    console.log(super); //  
  }
}
  • superが関数として呼び出されると、親のコンストラクション関数を表します.ES 6は、サブクラスのコンストラクション関数がsuoer関数を1回実行しなければならないことを要求する.
    superは親クラスの構造関数を表しますが、サブクラスのインスタンス、すなわちsuper内部のthisはサブクラスのインスタンスを返します.したがってsuperは親に相当する.prototype.constructor.call(this).
    class A {}
    
    class B extends A {
      constructor() {
        super();
      }
    }
    
    を関数とする場合,super()はサブクラスのコンストラクション関数にしか使用できず,他の場所で使用するとエラーが報告される.
    class A {}
    
    class B extends A {
      m() {
        super(); //  
      }
    }
    
  • superをオブジェクトとする場合、一般的な方法では、親のプロトタイプオブジェクトを指す.静的メソッドでは、親を指します.
    class A {
      p() {
        return 2;
      }
    }
    
    class B extends A {
      constructor() {
        super();
        console.log(super.p()); // 2。 A.prototype.p()
      }
    }
    
    let b = new B();
    
    一般的なメソッドでは、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 。
    
    属性が親クラスのプロトタイプオブジェクトに定義されている場合、superは取得できます.
    class A {}
    A.prototype.x = 2;
    
    class B extends A {
      constructor() {
        super();
        console.log(super.x) // 2
      }
    }
    
    let b = new B();
    
    ES 6は、サブクラスの一般的なメソッドで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();// super.print.call(this)
      }
    }
    
    let b = new B();
    b.m() // 2
    
    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は親のプロトタイプオブジェクトではなく親を指します.
    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によって親クラスのメソッドが呼び出されると、メソッド内部の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
    

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

    クラスのprototypeプロパティと_proto__属性:
    ほとんどのブラウザのES 5実装では、各オブジェクトに__があります.proto__プロパティ.対応するコンストラクション関数のprototypeプロパティを指します.
    Classはコンストラクション関数の構文糖としてprototype属性と_proto__を選択すると、2つの継承チェーンが同時に存在します.
  • サブクラスの_proto__プロパティ.コンストラクション関数の継承を表し、常に親を指します.
  • サブクラスprototypeプロパティの_proto__プロパティ、メソッドの継承を表し、常に親クラスのprototypeプロパティを指します.

  • 1つのオブジェクトとして、サブクラスのプロトタイプ(_proto__属性)は親であることが理解される.コンストラクション関数として、サブクラスのプロトタイプオブジェクト(prototypeプロパティ)は、親クラスのプロトタイプオブジェクト(prototypeプロパティ)のインスタンスです.
    class A {
    }
    
    class B extends A {
    }
    
    B.__proto__ === A // true
    B.prototype.__proto__ === A.prototype // true
    

    このような結果は,クラスの継承が次のようなパターンで実現されるためである.
    class A {
    }
    
    class B {
    }
    
    // B   A  
    Object.setPrototypeOf(B.prototype, A.prototype);// B.prototype.__proto__ = A.prototype;
    
    // B   A  
    Object.setPrototypeOf(B, A);
    
    const b = new B();// B.__proto__ = A;
    

    インスタンスの_proto__属性:
    サブクラスインスタンスの_proto__属性の_proto__属性、親インスタンスへの_proto__プロパティ、すなわち、サブクラスインスタンスのプロトタイプのプロトタイプは、親インスタンスのプロトタイプです.
    var p1 = new Point(2, 3);
    var p2 = new ColorPoint(2, 3, 'red');
    
    p2.__proto__ === p1.__proto__ // false
    p2.__proto__.__proto__ === p1.__proto__ // true
    

    したがって、サブクラスインスタンスの_proto__.__proto__プロパティ.親インスタンスの動作を変更できます.
    p2.__proto__.__proto__.printName = function () {
      console.log('Ha');
    };
    
    p1.printName() // "Ha"