ES6 では、JavaScript の「クラス」という概念が導入されました。これは、他のプログラミング言語のクラスとは異なります。ここで言うクラスとは、すでにデータが含まれているオブジェクト、そのデータに関連付けられているプロパティ、そのデータの操作に関連するメソッドを作成するためのテンプレートとして機能する特別な関数です。これらのオブジェクト、プロパティ、メソッドは、まとめてクラスの「メンバー」と呼ばれます。
クラスを定義するには、class
キーワードを使用します。JavaScript の組み込みコンストラクタ関数で確立されているおすすめの方法と規則に従って、クラスの識別子は大文字で始めます。
class MyClass {}
クラスの目的は、プロトタイプとコンストラクタ関数の高度な機能を、よりアクセスしやすい方法で操作できるようにすることです。
class MyClass {}
typeof MyClass;
> "function"
高度な JavaScript 機能をより簡単で魅力的なものにするためにクラスが追加されたことから、「糖衣構文」と呼ばれることもあります。ただし、クラスは、プロトタイプの継承の操作に便利な簡略記を提供するだけではありません。クラス構文の導入により、下位互換性の問題を引き起こすことなく、JavaScript の設計上の長年の問題に対処できるようになりました。一例として、クラスの本文内のすべてのコードは常に厳格モードで評価されます。
クラスのインスタンスを作成するには、new
演算子を使用します。
class MyClass {}
const myClassInstance = new MyClass();
myClassInstance;
> Object { }
クラスの本体内で定義された関数は、そのクラスの各インスタンスのメソッドとして公開されます。
class MyClass {
classMethod() {
console.log( "My class method." );
}
}
const myClassInstance = new MyClass();
myClassInstance.classMethod();
> "My class method."
クラス内で定義されたメソッドは、結果として得られるインスタンスのプロトタイプでメソッドになります。プロトタイプ チェーンの性質上、結果のオブジェクトに対してこれらのメソッドを直接呼び出すことができます。
class MyClass {
classMethod() {
console.log( "My class method." );
}
}
const myClassInstance = new MyClass( "A string." );
myClassInstance;
> Object { }
<prototype>: Object { … }
classMethod: function classMethod()
constructor: class MyClass { constructor(myPassedValue) }
<prototype>: Object { … }
myClassInstance.classMethod();
> "My class method."
クラスのインスタンスを作成すると、特別な constructor()
メソッドが呼び出されます。このメソッドは、新しく作成されたインスタンスに必要な「セットアップ」を行い、それに関連するプロパティを初期化します。インスタンスの作成時にクラスに渡される引数はすべて、constructor()
メソッドで使用できます。
class MyClass {
constructor( myPassedValue ) {
console.log( myPassedValue );
}
}
const myClassInstance = new MyClass( "A string." );
> "A string."
クラスの本体内では、this
の値はインスタンス自体を参照し、this
で定義されたプロパティは、そのクラスの各インスタンスのプロパティとして公開されます。
class MyClass {
constructor( myPassedValue ) {
this.instanceProperty = myPassedValue;
}
}
const myClassInstance = new MyClass( "A string." );
myClassInstance;
> Object { instanceProperty: "A string." }
これらのプロパティは、クラスの本体内のすべてのメソッドでも使用できます。
class MyClass {
constructor( myPassedValue ) {
this.instanceProp = myPassedValue;
}
myMethod() {
console.log( this.instanceProp );
}
}
const myClassInstance = new MyClass( "A string." );
myClassInstance.myMethod();
> "A string."
クラスの constructor()
を定義していない場合、JavaScript エンジンは空の「デフォルト」の constructor
を想定します。各クラスには、constructor()
という名前の特別なメソッドを 1 つだけ含めることができます。
class MyClass {
constructor() {}
constructor() {}
}
> Uncaught SyntaxError: A class may only have one constructor
クラスを定義するには、クラス宣言またはクラス式を使用します。これまでの例はすべてクラス宣言でしたが、ここでは new
を使用して名前を呼び出す必要があります。クラス式には、名前を付けることも、名前を付けずに「匿名」クラスを作成することもできます。
let ClassExpression = class {
constructor() {}
};
ClassExpression;
> class {}
匿名クラス式を使用できるのは、「オンザフライ」でクラスを構築する関数です。
function classMaker() {
return class {
constructor() {}
};
}
let MyVariable = classMaker();
MyVariable;
> class {}
クラス宣言を使用してクラスを再宣言すると、構文エラーが発生します。
class MyClass {
constructor( ) {
console.log( "My class." );
}
};
class MyClass {
constructor() {
console.log( "My new class." );
}
};
> Uncaught SyntaxError: redeclaration of class MyClass
ただし、クラス式を使用すると、クラスを再定義できます。
let ClassExpression = class MyClass { };
ClassExpression = class MyOtherClass {
constructor( myString ) {
this.myProp = myString;
}
};
new ClassExpression( "String." );
> MyOtherClass {myProp: 'String.'}
クラス宣言とは異なり、名前付きクラス式を名前で呼び出すことはできません。ただし、クラス式に割り当てられた名前は、作成されたインスタンスのプロパティとして使用できます。これは主にデバッグを容易にするために行われます。
let MyVariable = class MyClass {};
MyClass;
> Uncaught ReferenceError: MyClass is not defined
MyVariable;
> class MyClass {}
MyVariable.name;
> "MyClass"
クラス式を使用して変数を初期化すると、その変数のホイスティング ルールが想定どおりに適用されます。クラス宣言は、let
および const
と同じ「時間的デッドゾーン」ルールに従い、現在のスコープの一番上にホイスティングされていないかのように動作します。つまり、クラス宣言の前にクラスを呼び出すと、エラーが発生します。
{
let myVar = new MyClass( "Property string." );
class MyClass {
myProp;
constructor( myString ) {
this.myProp = myString;
}
};
};
> Uncaught ReferenceError: Cannot access 'MyClass' before initialization
理解度をチェックする
クラスを正しく定義しているのは、次のうちどれですか。
class MyClass {}
myClass = class {}
new class()
1 つのクラスに constructor()
メソッドをいくつ使用できますか。