オブジェクト指向プログラミングと聞くと少し難しいイメージがありますが、簡単に言うと「自分のことは自分でできるようにオブジェクトに機能を持たせる」ということです。
このオブジェクト指向プログラミングは他のプログラミング言語(Java、Python、C#、C++、Ruby、PHPなど)でも使用されるため、ここで理解しておけばで他の言語でも活かすことができます。
今回の学習内容
オブジェクト指向の考え方
以前、JavaScriptの基礎でオブジェクトについて学習しました。(まだの方はオブジェクトと関数(変数スコープの説明あり)を御覧ください)
例えば、人である「らくま たろう」さんをオブジェクトにしてみると以下のようになります。
{
firstName: 'Taro',
lastName: 'Rakuma'
}
では、このデータのフルネームをコンソールに表示する処理を書く場合、どう書きますか?
const user = {
firstName: 'Taro',
lastName: 'Rakuma'
}
console.log(user.firstName + ' ' + user.lastName);
こう書けば簡単に実装できますね。
ただ、オブジェクト指向の場合はこうではありません。冒頭でも書いている通り、オブジェクト指向は「自分のことは自分でできるように」設計します。
上記処理をオブジェクト指向で書いたら以下のようになります。
const user = {
firstName: 'Taro',
lastName: 'Rakuma',
fullname: function() {
console.log(this.firstName + ' ' + this.lastName);
}
}
user.fullname();
フルネームをコンソールに表示するという処理そのものをオブジェクトに持たせました。
このようにオブジェクト自身の処理はオブジェクトが持つことで処理の追記や呼び出し、メンテナンス、テストが簡単になるといった利点があります。
クラスの使い方
先程の例ではJavaScriptの値であるオブジェクト型に関数を設定しましたが、通常は class
(クラス)を定義して使用します。
なぜ class
を使用する必要があるのか考えてみましょう。
例えば、先程の例で使用した「人」のデータが以下のように配列で来た場合どうしますか?
[
{
firstName: 'Taro',
lastName: 'Rakuma'
},
{
firstName: 'Hanako',
lastName: 'Rakuma'
}
]
それぞれのオブジェクトに fullname
関数を設定するのはちょっと手間が掛かりますね。
この様な場合に class
という設計図を予め作成しておくことができます。
クラスの作成
class
を解説します。それ以前のバージョンでの実装方法は、カスタムオブジェクトを参照にしてください。
オブジェクト指向 JavaScript 入門 - JavaScript | MDN
class
を使用する場合は、予め定義しておく必要があります。
先程の例を元に class
を定義してみます。
class User {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
fullname() {
console.log(this.firstName + ' ' + this.lastName);
}
}
これで class
という設計図を定義することができました。
インスタンス化
この class
を使用する場合は、この設計図にデータを与えてオブジェクト(インスタンス)を生成する必要があります。
このことを インスタンス化 と言います。
// インスタンス化
const user = new User('Taro', 'Rakuma');
// メソッド呼び出し
user.fullname();
クラス名について
class
のあとは クラス名 を指定します。このクラス名は他のクラス名と同じ名前を付けることはできません。
また頭文字を大文字にしたキャメルケースで命名します。
例: Animal
、TimeZone
コンストラクタについて
constructor
(コンストラクタ)は class
のインスタンスを生成する時に一度だけ実行されます。
一番最初に実行されるので初期化処理を記述します。
また constructor は class
で一つしか定義できません。
メソッドについて
class
内の関数のことを method
(メソッド)と呼びます。
fullname()
のようなメソッドは インスタンスからしか呼び出すことができませんが、
static sayHello()
のように頭に static
を付けると静的メソッドとなりインスタンス化する前のみ呼び出すことが出来るメソッドを定義できます。
class User {
constructor() {
// 初期化...
}
static sayHello() {
console.log('こんにちは');
}
}
User.sayHello(); // インスタンス化前のみ呼び出し可能
プロパティについて
constructor
内で初期化している this.firstName
などはインスタンスのプロパティと呼ばれ、このインスタンスが持つ変数となります。
class
内では this.プロパティ名
で参照することができます。
インスタンスからは、インスタンス名.プロパティ名
で参照できます。
また、constructor
だけではなく、以下のように予めプロパティを設定することができます。
class User {
firstName = ''; // プロパティ
lastName = ''; // プロパティ
constructor(firstName, lastName) {
// this. を先頭につけて参照
this.firstName = firstName;
this.lastName = lastName;
}
}
// インスタンス化
const user = new User('Taro', 'Rakuma');
// インスタンス名.プロパティ名 で参照
console.log(user.firstName); // Taro
class
内でしか参照できないプライベートフィールドを宣言することができます。その場合は、プロパティの宣言時に先頭に
#
を付けて宣言します。例:
#gender = 'unknown';
このプライベートフィールドにはゲッターやセッターを利用してアクセスします。
より詳しいドキュメントはクラス - JavaScript | MDNのプライベートフィールドを参照してください。
継承について
クラスの特徴を引き継いだ派生した新しい class
を定義することを継承と言います。
この基となるクラスをスーパークラス と呼び、派生したクラスを サブクラス と呼びます。
継承には extends
を使用し、一つの class
からしか継承することはできません。
class AppUser extends User {
constructor(userData) {
super(userData.firstName, userData.lastName);
this.id = userData.id;
this.email = userData.email;
this.avatar = userData.avatar;
}
}
let user = new AppUser(userDaya);
user.fullname();
スーパークラスを呼び出すsuper
スーパークラスとサブクラスには親子関係ができます。
super
を使用して 子から親のメソッドを呼び出すことができます。
例: super.メソッド()
上の例では コンストラクタ で super()
とすることで、親の コンストラクタ を実行しています。
継承を行っている場合、この呼び出しは、コンストラクタで一番最初に行わなければなりません。
オーバーライド
サブクラスにはスーパークラスと同名のメソッドを作成することができます。作成後に、サブクラスでこの同名のメソッドを呼び出した場合は、スーパークラスではなくサブクラスのメソッドが使用されます。
これをオーバーライドといいます。
課題
プロパティに name
(文字列) と weight
(数値)があり、コンストラクタで初期化するクラス Animal
を作成してください。
Animal
に プロパティ weight
を0.5
ずつ増加させる eat
メソッドを作成してください。
また増加後の weight
をコンソールに表示するように eat
メソッド内に記述してください。
クラス Animal
を{name: 'ココ', weight: 500}
のデータでインスタンス化してください。
課題3でインスタンス化したオブジェクトで、メソッド eat
を実行し、weight
が 0.5
増えたことを確認してください。
クラスAnimal
を継承した クラスDog
を作成してください。
この時 eat
メソッドをオーバーライドして、増加させる weight
を 1
に変更してください。
クラスDog
を次のデータでインスタンス化してください。
{name: 'ポチ', weight: 2000}
インスタンス化したクラスDog
のオブジェクトの eat
メソッドを実行して、weight
が 2001
となることを確認してください。