クラスの扱い方
クラスの扱い方
本記事について
要約
このページでは、JavaScriptのクラスという概念について説明しています。JavaScriptのクラスは、オブジェクト指向プログラミングを可能にする構造です。クラスは設計図のようなもので、そのクラスから生成される各オブジェクト(クラスのインスタンス)が持つべき特性(プロパティ)と行動(メソッド)を定義します。
クラスを作るときは、class
キーワードを使って定義します。また、クラス内部にメソッドを定義することもできます。たとえば、クラスのインスタンスが特定のアクションを実行することを指示できます。
また、クラスは継承という概念を使って他のクラスから特性を引き継ぐことができます。これにより、一般的な特性を持つクラス(スーパークラス)を定義し、それを特化した形で再利用する(サブクラスを作る)ことが可能になります。
以上がJavaScriptのクラスについての基本的な説明です。この理解を深めるためには、具体的なコードを書いてみることをおすすめします。
前提
Trailheadの英語版をChatGPT4(以下、ChatGPT)に投げて返ってきた内容を載せています。もともとはTrailheadのみで学習していたのですが、不自然な日本語や、JavaScript初学者に理解しづらい用語・概念を手っ取り早く調べるとためにChatGPTとやり取りしながらの学習に切り替えました。
ChatGPTに聞くとおおよそ同じような答えが返ってきますが、毎回聞くのも手間ですし、用語なども追加で聞いていることもあるので備忘録を兼ねて残します。
僕と同じようなJavaScript初学者の方に参考になれば幸いです。
対象のTrailhead↓
Work with Classes 単元 | Salesforce Trailhead
学習目標
このユニットを終えたら、あなたは次のことができるようになります:
- ES6以降でのクラスの作成と呼び出し方の違いを説明する。
- クラスの一般的に使用されるメンバーをリスト化する。
- 基底クラスと派生クラスの違いを明確に理解する。
クラスのように見えるもの…
ES6以前にJavaScriptでクラスを作成したい場合、プロトタイプを使用して以下のような処理を行いました:
function Animal(name) {
this.name = name;
}
Animal.prototype.printName = function() {
console.log(this.name);
}
この例では、プロトタイプベースのコンストラクタ関数Animal
が作成されています。関数名に大文字の"A"が使われ、引数はthis
キーワードに割り当てられます。これが他の開発者にAnimal
がただの関数ではないことを知らせる唯一の手がかりです。クラスのインスタンス化とprintName
関数の呼び出しは以下のように行います:
let duck = new Animal('duck');
duck.printName(); // "duck"と表示されます
もし他の言語から来たのであれば、あなたはクラスベースの継承に慣れているでしょう。しかし、JavaScriptはそれとは異なる動作をします。JavaScriptが少なくともクラスベースの言語のように見えるようにする試みとして、ES6ではclass
キーワードが導入されました。この新しい構文を使用すると、Animal
クラスは以下のように定義できます:
class Animal {
constructor(name) {
this.name = name;
}
printName() {
console.log(this.name);
}
}
重要な点は、class
キーワードが使用されているにもかかわらず、生成されるオブジェクトは依然として関数であるということです。次のコードを実行すると、コンソールに表示されるのは"type"ではなく"function"となります。
console.log(typeof Animal); // "function"と表示されます
クラスからインスタンスを生成し、メソッドを使用する方法は、コンストラクタ関数の場合と全く同じです。まあ、ある程度は。ES5のコンストラクタ関数ではnew
キーワードはオプショナルでしたが、現在では必
須です。クラスを使用する際にnewキーワードを省略すると、TypeErrorがスローされます。
もう一つの違いは、関数宣言は巻き上げることができるということです。つまり、まだ宣言されていない関数を呼び出すことができます。クラスではこのようなことは許されていません。クラスは、その定義が評価された後でしかアクセスできません。
クラスは以下の種類のメンバーを含むことができます。
メンバー | 説明 | 例 |
---|---|---|
コンストラクタ | コンストラクタは、クラスの新しいインスタンスを作成する際に自動的に実行されます。初期化関数が常に呼び出されることを保証します。これにより、クラスの状態が有効に保たれます。ただし、コンストラクタを作成する必要はありません。もし含まれていない場合、JavaScriptエンジンが空のものを作成します。 | constructor(name) { this.name = name; } |
静的メソッド | 静的メソッドはクラスのインスタンスの一部ではなく、インスタンスを参照せずにこれらのメソッドを参照することができます。静的クラスメンバーの概念はES6には新しくありませんが、static キーワードは新しいです。ES6以前には、静的にしたいメソッドをコンストラクタに置く必要がありました。しかし現在では、クラスのどこでもstatic キーワードを使用して配置できます。 |
static methodName() { return ‘something’; } |
プロトタイプメソッド | これらのメソッドはstatic キーワードを含まず、インスタンスで参照する必要があります。 |
printName() { console.log(this.name); } |
ゲッターとセッター | これらのアクセッサ関数はオブジェクトリテラルのように動作し、ES5での動作と同じです。基本的には、プロパティ名の前にget とset キーワードを置くだけです。セッターなしでゲッターを定義すると、そのプロパティは読み取り専用になります。 |
get area() { return this.height * this.width; } set area(value) { this.area = value; } |
覚えておく
べき最も重要なことは、ES6のクラスが伝統的なオブジェクト指向のクラスのように見えるとしても、そうではないということです。新しいclass
キーワードがあっても、それらはまだJavaScriptのプロトタイプベースの継承に基づいています。
継承について話すと
継承について触れたので、新しい構文でそれがどのように動作するのか気になるかもしれません。ES6のクラスは継承をずっと簡単で直感的にしています。
クラスには基底クラスと派生クラスの2つのバリエーションがあります。その違いはextends
キーワードにあります。派生クラス(またはサブクラス)にはそれがあり、基底クラスにはありません。例えば、以下のParent
という名前の基底クラスを見てみてください。
class Parent {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
あなたがParent
クラスの機能を拡張したChild
という名前のサブクラスを作成する必要があるとします。それはこんな感じになるかもしれません:
class Child extends Parent {
constructor(name) {
super(name);
}
getMessage() {
return 'Hello ' + super.getName();
}
}
let someone = new Child('person');
console.log(someone.getMessage()); // "Hello person"と表示されます
このコードをPlayCodeにコピーペーストすると、コンソールには"Hello person"というフレーズが表示されます。Child
クラス定義中のextends
キーワードは、それが派生クラスであることを示しています。
また、親のコンストラクタや基底クラスからのメソッド定義を参照することができるsuper
キーワードの使用にも注意してください。super
キーワードを見たら、あなたは派生クラスにいて、基底クラスを参照していることを知ることができます。
さらに詳しく
- オブジェクト内でメソッド定義を分離するためにコンマが使用される一方、クラスでは許可されていません。
- クラスは以下のように式を使用して定義することもできます:
const myAnimal = class Animal {
constructor(name) {
this.name = name;
}
printName() {
console.log(this.name);
}
}
printNameメソッドはこのように呼ばれます。
let duck = new myAnimal('duck');
duck.printName(); // "duck"と表示されます