ES6(ES2015) から、JavaScript でも C++, PHP, Python などの言語と似た class 定義が可能となりました。下記では、Animal という名前のクラスを定義しています。
class Animal { }
インスタンスを作成するには new
を用います。
var o1 = new Animal();
インスタンスを削除するには delete
を用います。ただし、var や let で宣言した変数は削除できず、通常モードであれば false を返し、Strictモードであればエラーとなります。
o1 = new Animal(); var o2 = new Animal(); let o3 = new Animal(); delete o1; // 通常モードだと消える。Strictモードだと o1 自体を作成できない。 delete o2; // 通常モードだとエラーにはならないが消えない。Strintモードだとエラー delete o3; // 通常モードだとエラーにはならないが消えない。Strictモードだとエラー
constructor() は、オブジェクトを生成する際に初期化関数として呼ばれるメソッドを定義します。下記の例では、オブジェクト生成時に種別(type)引数を渡し、オブジェクト内部のメンバ変数(this.type)に記録しています。
class Animal {
constructor(type) {
this.type = type;
}
}
var o1 = new Animal("Cat");
console.log(o1.type); // => Cat
クラスはクラスフィールドを持つことができます。クラスフィールドはコンストラクタの中で初期化します。
class Animal {
constructor(type) {
this.type = type;
}
}
var o1 = new Animal("Cat");
console.log(o1.type); // => Cat
ES2022 からはコンストラクタが無くても宣言・初期化することができるようになりました。
class Animal { type = "unknown"; }
クラス定義の中では、メソッドを定義することができます。メンバ関数は、オブジェクト.メンバ関数名() の形式で呼び出します。メソッドを定義する際は、function は不要です。
class Animal {
setType(type) {
this.type = type;
}
getType() {
return this.type;
}
}
var o1 = new Animal();
o1.setType("Cat");
console.log(o1.getType()); // => Cat
ES2022 からはフィールド名やメソッド名の先頭に # をつけることで、クラスの外部からアクセスできないプライベートフィールド、プライベートメソッドを定義できるようになりました。クラスの外部で不用意に変更されることがなくなるため、プログラムの安全性を高めることができます。
class Aminal { #type = "unknown"; #func() { .... } } var o1 = new Animal(); console.log(o1.#type); // エラー o1.#func(); // エラー
static は、スタティックフィールドやスタティックメソッドを定義します。スタティックフィールドやスタティックメソッドは、オブジェクトを生成しなくても、className.fieldName や className.methodName() で参照することができます。
class Animal { static msg = "Hello!"; static hello() { console.log("Hello!"); } } console.log(Animal.msg); // => Hello! Animal.hello(); // => Hello!
スタティックフィールドの初期化に式や文を使用したい場合、これまではクラス定義の外に記述する必要がありました。
class Foo { static x = 123.4; static y; } Foo.y = Foo.x * 2;
ES2022 ではこれをスタティックイニシャライズブロックとしてクラス定義内に記述できるようになりました。
class Foo { static x = 123.4; static { Foo.y = Foo.x * 2; } }
get はゲッター(getter)、set はセッター(setter)を定義します。ゲッター・セッターは、クラス利用者に対してはプロパティ(属性)のように簡単に代入や参照ができ、かつ、クラス開発者にとっては、代入・参照の際にメソッドがコールされ、代入・参照時にログを記録したり複雑な内部処理を実行することが可能となります。
class Animal { get type() { console.log("get:" + this._type); return this._type; } set type(arg) { console.log("set:" + arg); this._type = arg; } } var o1 = new Animal(); o1.type = "Cat"; // setter メソッドが呼ばれる console.log(o1.type); // getter メソッドが呼ばれる
prototype を用いて、定義済のクラスに変数やメソッドを追加することができます。
class Animal { } Animal.prototype.type = "Unknown"; Animal.prototype.hello = function() { console.log("Hello!"); } var o1 = new Animal(); console.log(o1.type); o1.hello();
クラスは継承することができます。継承元をスーパークラス(親クラス)、継承先をサブクラス(子クラス)と呼びます。Animal クラスを親クラスとして、Cat という子クラスを定義するには extends を用いて次のようにします。子クラスでは、親クラスのメソッドや変数を継承することができます。
class Animal { hello1() { console.log("Hello!"); } } class Cat extends Animal { hello2() { console.log("Hello Hello!"); } } var o1 = new Cat(); o1.hello1(); // => Hello! o1.hello2(); // => Hello Hello!
super() は親のコンストラクタを呼び出します。super() は最初に使用する this よりも先に呼び出す必要があります。
class Animal { constructor(type) { this.type = type; } } class Cat extends Animal { constructor(name) { super("Cat"); this.name = name; } } var o1 = new Cat("Mii-chan"); console.log(o1.type); // => Cat console.log(o1.name); // => Mii-chan
子クラスのコンストラクタを省略すると、子クラス作成時の引数を使用して親クラスのコンストラクタが自動的に呼び出されます。これは、constructor(...args) { super(...args); } と同じ動作となります。
class Animal {
constructor(name) {
this.name = name;
}
}
class Cat extends Animal {
// constructor(...args) { super(...args); }
}
var o1 = new Cat("Mii-chan");
console.log(o1.name); // => Mii-chan
下記の様にして、親クラスのメソッドを呼び出すこともできます。
class Animal {
hello() {
console.log("Hello!");
}
}
class Cat extends Animal {
hello() {
super.hello();
}
}
var o1 = new Cat();
o1.hello(); // => Hello!
下記の様にクラス式を用いて、クラス名を持たない匿名クラスを作成することができます。
var o1 = class {
constructor() {
this.type = "Cat";
}
};
console.log(o1.type); // => Cat