JavaScript では関数を使ったり変数を使ったり、割と自由にコードを書くことができますが、言語としてベースになっているのはオブジェクト指向です。
今回はJavaScript のオブジェクト指向について調べてまとめていこうと思います。
▼ JavaScript のオブジェクト指向がいかに便利かをこちらの記事でもまとめています
オブジェクト指向とは
JavaScript のオブジェクト指向について触れる前に、まずはオブジェクト指向そのものがどんなものか見ていきましょう。(いくつかサイトを覗いてみたのですが、「オブジェクト指向難しすぎる」ばっかり書いてあって震えています。)
MDN の「初心者のためのオブジェクト指向 JavaScript | MDN」は難しい部分を全て省いた説明になっている(本人談)ようなのでこちらを参考に調べていこうと思います。
OOP の基本的な考え方は、プログラムの中で扱いたい、現実世界の事物を模るためにオブジェクトを使用すること、またはそうしなければ使うことが難しいあるいは不可能だった機能にアクセスするための、シンプルな方法を提供することです。
初心者のためのオブジェクト指向 JavaScript | MDN
オブジェクト指向について説明する時にはよく実物のもの、例えば車やたい焼きなどが挙げられます。またゲームでキャラクターや敵キャラを生成するときにもオブジェクトが使われることは多いでしょう。そもそもオブジェクトが現実世界を模すために存在するためですね。
まとめ
オブジェクトは現実世界をプログラムで表すためのもの
オブジェクトインスタンス
オブジェクト指向について調べていると「インスタンス」という言葉をよく見かけますね。インスタンスは設計書をもとに作成された実物です。
引用: 初心者のためのオブジェクト指向 JavaScript | MDN
ここでは Person クラス(設計書)から実際の人物(インスタンス)を作成しています。ちょっとサイコですね。
ただプログラムの世界であれば会員登録したユーザーであったり、ゲームのキャラクターであったりをこのようなクラスから生成することができそうです。
クラスからインスタンスを生成することを インスタンス化と言います。
またクラスからインスタンスが生成される時には コンストラクター関数 と呼ばれる関数が実行されます。
まとめ
- インスタンス化: 設計書から実物を作ること
- インスタンス: 設計書から生成された実物
- コンストラクター関数: インスタンス化の際に実行される関数
子クラスとポリモーフィズム
オブジェクトからはインスタンスを生成することができます。
そしてオブジェクトの楽しいポイントなのですが、元となるクラスからさらに進化したクラスを作ることができます。
先ほどの Person クラスを拡張してみましょう。
引用: 初心者のためのオブジェクト指向 JavaScript | MDN
例えば学校の名簿を作りたいとき、Person だけでは必要な情報を詰め込めないですね。先ほどの Person クラスは実体が人間であることしか想定していないので汎用的ですが、一方で「この人は何の教科を教えるのか」というようなニッチなステータスは想定していないわけです。
Teacher クラスを作ることでより具体的に性質を定義できますね。
当然ですが子クラスもインスタンスを生成できます。
引用: 初心者のためのオブジェクト指向 JavaScript | MDN
そしてその人が持つステータスによってあいさつを変えたいですね。先生はちょっと固い挨拶、生徒はフランクな挨拶。門番は町の名前を教えてくれて、武器屋は武器を売り込んでくれる。
そんなときも Person クラスで Greeting という関数を作成しているので、子クラスでブラッシュアップして使うことができます。こうした原理は ポリモーフィズム と言います。
まとめ
- 子クラス: 元となるクラスからさらに進化したクラス
- ポリモーフィズム: 元となるクラスでベースとなるコードを作成しておいて、子クラスでそのまま使用したり、アレンジして使ったりできる原理
JavaScript におけるオブジェクト指向
JavaScript はオブジェクト指向がベースとなっている言語であり、オブジェクト指向なしには語れません。といったことをとてもわかりやすく書いてあるブログを見つけたので今度はこちらを参照しながらまとめていきます: JavaScriptで気楽に始めるオブジェクト指向プログラミング
手続き型プログラミングとは
オブジェクト指向の話に入る前に、まずは「手続き型プログラミング」について知らなければなりません。手続き型プログラミングというのは、データがあって、関数があって、それらの命令を上から順番に実行していくようなプログラミングの手法です。
……ええと、つまり手続き型プログラミングというのは普通のプログラミングでは?と思った方、その通りです。全くその通りです。全く普通のプログラミング手法のことを、手続き型プログラミングと呼ぶのです。
JavaScriptで気楽に始めるオブジェクト指向プログラミング
以下のようなコードは手続き型プログラミングで書かれています。変数や関数を使いながら段階を踏んで計算していってますね。
function calcCircleArea(radius) {
return radius * radius * Math.PI;
}
const r = 5;
const area = calcCircleArea(r);
手続き型プログラミングはオブジェクト指向と対立する概念ではなく両方取り入れることも可能で、現に上のようなコードはあなたも JavaScript で書いたことがあると思います。
では下のようなコードはどうでしょう?
// 配列をソートする関数。
// 難しいので中身は理解しなくても良い。
function sort(array, length) {
for(let i = 0; i < length; i++) {
for(let j = length - 1; j > i; j--) {
if(array[j] < array[j-1]) {
[array[j], array[j-1]] = [array[j-1], array[j]];
}
}
}
}
const a = [3, 6, 10, 4, 8, 1];
const len = 6;
sort(a, len);
// 引用: https://sbfl.net/blog/2017/06/09/javascript-easy-oop/
書いたことあるような、でもないような感じですね。
おそらく「こんな面倒くさいことしてないで sort
メソッド使えばいいじゃん」と思ったのではないでしょうか?
こんなふうに ↓
const a = [3, 6, 10, 4, 8, 1];
const b = a.sort((a, b) => a - b);
// 引用: https://sbfl.net/blog/2017/06/09/javascript-easy-oop/
はい。これがオブジェクト指向的な書き方です。
JavaScript では配列のようなデータ型に元となるオブジェクトが用意されています。先ほどの Person クラスでは以下のようになっていましたね。
Person --> Teacher --> teacher1, teacher2...
--> Student --> student1, student2...
配列の場合はざっくり書くとこうです。
Array --> array1, array2...
配列1つひとつが Array という元となるクラスのインスタンスになっているので sort
メソッドが使えるんですね。データと処理がひとセットにまとまってくれているイメージですね。これはかなりのハッピーセットですよ。
▼ 詳しくは以下の記事で解説しているのでよければこちらもどうぞ
まとめ
便利なメソッドはJavaScript がオブジェクト指向だから使える
Class を使って自分でプロトタイプのオブジェクトを作成する
ここまでのまとめとなりますが、そしてオブジェクト指向には元となるクラスというものが存在し、子クラスを作ったり、インスタンスを生成したりできます。
そしてJavaScript はオブジェクト指向がベースとなっており、みんなオブジェクト指向の恩恵を受けています。
それだけでもとっても便利なのですが、最初から用意されているビルトインのクラスだけでなく、独自にクラスを作成することもできるんです。
そのときに使うのが class
キーワードですね。
※ function を使うこともありますが今回は割愛します
Person クラスを実装してインスタンスを生成してみましょう。
class Person {
constructor(firstName, lastName) {
this.name = `${firstName} ${lastName}`;
}
greeting() {
return `Hi! I'm ${this.name}`
}
}
const kotaro = new Person("kotada", "kotaro");
console.log(kotaro.greeting()); // -> "Hi! I'm kotada kotaro"
まずクラスからインスタンスが生成されるときにコンストラクタ関数が動くんでしたね。ここでは name というプロパティに ${firstName} ${lastName}
を入れるよ、という内容です。
そしてあいさつをしてくれる greeting 関数はきちんと私の名前を入れてあいさつしてくれていますね。
せっかくなので子クラスも作っちゃいましょう。
class Hero extends Person {
constructor(firstName, lastName, kosei) {
super(firstName, lastName);
this.kosei = kosei;
}
greeting() {
return `${super.greeting()}. My Quirks is ${this.kosei}.`;
}
}
const deku = new Hero("midoriya", "izuku", "One-for-All");
console.log(deku.greeting());
Heroという命名が良くないのですがヒロアカファンの方許してください。一旦忘れましょう
子クラスを作成するときに大切なのが extends
キーワードと super
関数です。
class Hero extends Person
で 「この Hero クラスは Person クラスの子クラスですよ」と示しています。
その後 constructor
と greeting
の中で super
という関数が出てきていますね。これは親クラスを受け継ぐよという意味です。 constructor
のなかで super(firstName, lastName)
としているのは「親クラスのコンストラクターを引き継ぐよ。コンストラクターには firstName
、lastName
を渡してね」という意味です。ただ全部そのまま受け継いでしまっては子クラスの意味がないので、アレンジとして kosei
(個性)を追加しています。
まとめ
- class キーワードを使ってクラスを作成できる
- 子クラスを作るために
extends
を使用する - 親クラスから機能を引き継ぐために
super()
を使用する
この記事のまとめ
- オブジェクトは現実世界をプログラムで表すためのもの
- インスタンス化: 設計書から実物を作ること
- インスタンス: 設計書から生成された実物
- コンストラクター関数: インスタンス化の際に実行される関数
- 子クラス: 元となるクラスからさらに進化したクラス
- ポリモーフィズム: 元となるクラスでベースとなるコードを作成しておいて、子クラスでそのまま使用したり、アレンジして使ったりできる原理
- 便利なメソッドはJavaScript がオブジェクト指向だから使える
- class キーワードを使ってクラスを作成できる
- 子クラスを作るために
extends
を使用する - 親クラスから機能を引き継ぐために
super()
を使用する