概要
ES6では、class(クラス)がオブジェクトのテンプレートとして導入され、class キーワードを使ってクラスを定義できます。
class の本質は function です。
これはシンタックスシュガーとみなすことができ、オブジェクトプロトタイプの書き方をより明確にし、オブジェクト指向プログラミングの構文により近づけます。
基本的な使い方
クラス定義
クラス式は匿名または名前付きにできます。
let Example = class {
constructor(a) {
this.a = a;
}
}
let Example = class Example {
constructor(a) {
this.a = a;
}
}
クラス宣言
class Example {
constructor(a) {
this.a = a;
}
}
注意点:繰り返し宣言はできません。
class Example{}
class Example{}
let Example1 = class{}
class Example{}
注意点
クラス定義は巻き上げ(ホイスティング)されません。つまり、アクセスする前にクラスを定義する必要があり、そうしないとエラーになります。
クラス内のメソッドに function キーワードは不要です。
メソッド間にはセミコロンを付けられません。
new Example();
class Example {}
クラスの本体
プロパティ
prototype
ES6 でも prototype は依然として存在します。クラス内で直接メソッドを定義できますが、実際にはメソッドは prototype 上に定義されます。メソッドのオーバーライド / 初期化時にメソッドを追加
メソッドの追加
Object.assign(Example.prototype,{
})
静的プロパティ
静的プロパティ:class 自体のプロパティ、つまりクラス内部に直接定義されるプロパティ( Class.propname )で、インスタンス化は不要です。
ES6 では、Class 内部には静的メソッドのみがあり、静的プロパティはないと規定されています。
class Example {
static a = 2;
}
Example.b = 2;
パブリックプロパティ
class Example{}
Example.prototype.a = 2;
インスタンスプロパティ
インスタンスプロパティ:インスタンスオブジェクト( this )に定義されるプロパティです。
class Example {
a = 2;
constructor () {
console.log(this.a);
}
}
name プロパティ
class の後に続くクラス名(存在する場合)を返します。
let Example=class Exam {
constructor(a) {
this.a = a;
}
}
console.log(Example.name);
let Example=class {
constructor(a) {
this.a = a;
}
}
console.log(Example.name);
メソッド
constructor メソッド
constructor メソッドはクラスのデフォルトメソッドであり、クラスのインスタンスオブジェクトを作成するときに呼び出されます。
class Example{
constructor(){
console.log('私はconstructorです');
}
}
new Example();
返されるオブジェクト
class Test {
constructor(){
}
}
console.log(new Test() instanceof Test);
class Example {
constructor(){
return new Test();
}
}
console.log(new Example() instanceof Example);
静的メソッド
class Example{
static sum(a, b) {
console.log(a+b);
}
}
Example.sum(1, 2);
プロトタイプメソッド
class Example {
sum(a, b) {
console.log(a + b);
}
}
let exam = new Example();
exam.sum(1, 2);
インスタンスメソッド
class Example {
constructor() {
this.sum = (a, b) => {
console.log(a + b);
}
}
}
クラスのインスタンス化
new
class のインスタンス化は必ず new キーワードを使用する必要があります。
class Example {}
let exam1 = Example();
インスタンス化されたオブジェクト
共有プロトタイプオブジェクト
class Example {
constructor(a, b) {
this.a = a;
this.b = b;
console.log('Example');
}
sum() {
return this.a + this.b;
}
}
let exam1 = new Example(2, 1);
let exam2 = new Example(3, 1);
console.log(Object.getPrototypeOf(exam1) === Object.getPrototypeOf(exam2));
Object.getPrototypeOf(exam1).sub = function() {
return this.a - this.b;
}
console.log(exam1.sub());
console.log(exam2.sub());
decorator
decorator は関数であり、クラスの動作を変更するために使われ、コードのコンパイル時に作用します。
クラスデコレータ
1つのパラメータ
最初のパラメータ target は、クラス自体を指します。
function testable(target) {
target.isTestable = true;
}
@testable
class Example {}
Example.isTestable;
複数のパラメータ——ネストによる実装
function testable(isTestable) {
return function(target) {
target.isTestable=isTestable;
}
}
@testable(true)
class Example {}
Example.isTestable;
インスタンスプロパティ
上記の2つの例で追加したのは静的プロパティです。インスタンスプロパティを追加するには、クラスの prototype 上で操作すればよいです。
メソッドデコレータ
3つのパラメータ:target(クラスのプロトタイプオブジェクト)、name(修飾するプロパティ名)、descriptor(そのプロパティの記述オブジェクト)。
class Example {
@writable
sum(a, b) {
return a + b;
}
}
function writable(target, name, descriptor) {
descriptor.writable = false;
return descriptor;
}
デコレータの実行順序
外から内に入り、内から外へ実行されます。
class Example {
@logMethod(1)
@logMethod(2)
sum(a, b){
return a + b;
}
}
function logMethod(id) {
console.log('evaluated logMethod'+id);
return (target, name, desctiptor) => console.log('excuted logMethod '+id);
}
カプセル化と継承
getter / setter
定義
class Example{
constructor(a, b) {
this.a = a;
this.b = b;
}
get a(){
console.log('getter');
return this.a;
}
set a(a){
console.log('setter');
this.a = a;
}
}
let exam = new Example(1,2);
class Example1{
constructor(a, b) {
this.a = a;
this.b = b;
}
get a(){
console.log('getter');
return this._a;
}
set a(a){
console.log('setter');
this._a = a;
}
}
let exam1 = new Example1(1,2);
console.log(exam1._a);
getter は単独で存在できません
class Example {
constructor(a) {
this.a = a;
}
get a() {
return this.a;
}
}
let exam = new Example(1);
getter と setter は同じレベルに存在する必要があります
class Father {
constructor(){}
get a() {
return this._a;
}
}
class Child extends Father {
constructor(){
super();
}
set a(a) {
this._a = a;
}
}
let test = new Child();
test.a = 2;
console.log(test.a);
class Father1 {
constructor(){}
get a() {
return this._a;
}
set a(a) {
this._a = a;
}
}
class Child1 extends Father1 {
constructor(){
super();
}
}
let test1 = new Child1();
test1.a = 2;
console.log(test1.a);
extends
extends を使用してクラスの継承を実現します。
class Child extends Father { ... }
super
サブクラスの constructor メソッド内には super が必要で、かつ this より前に記述する必要があります。
class Father {
constructor() {}
}
class Child extends Father {
constructor() {}
}
let test = new Child();
親クラスのコンストラクタの呼び出しは、サブクラスのコンストラクタ内でのみ使用できます。
class Father {
test(){
return 0;
}
static test1(){
return 1;
}
}
class Child extends Father {
constructor(){
super();
}
}
class Child1 extends Father {
test2() {
super();
}
}
親クラスのメソッドを呼び出す場合、super はオブジェクトとして、通常のメソッドでは親クラスのプロトタイプオブジェクトを指し、静的メソッドでは親クラスを指します。
class Child2 extends Father {
constructor(){
super();
console.log(super.test());
}
static test3(){
return super.test1+2;
}
}
Child2.test3();
注意点
通常のオブジェクトは継承できません。
var Father = {
}
class Child extends Father {
}
Object.setPrototypeOf(Child.prototype, Father);