こんにちは。uni-browserの財前航介です。
今日は、JavaScriptでオブジェクト指向を使う上での基礎となる、JavaScriptクラスのインスタンス生成について学んでいきましょう。
初心者の方にもわかるように、極力難しい言葉を使わずに説明できればと考えています!
JavaScriptってオブジェクト指向言語だったの!?
オブジェクト指向言語と言うと、JavaやRubyやPython、、、
色々な言語を思い浮かべる方がいらっしゃるでしょう。
しかし、現場でJavaScriptを使っていると、JavaScriptがオブジェクト指向言語であることを忘れてしまうこともあります。
と言うのも、開発現場によっては、JavaScriptは画面のちょっとした動きを実現するためだけに部分的に使われることも多く、がっつりソースコードで機能を作成するような場面が少ない場合もあるからです。
しかし、近年SPA(シングルページアプリケーション)などの台頭を背景に、Webクライアント側に多くの機能を移すことで、ネイティブアプリに近い機能を実現するWebアプリケーションも多くなっており、JavaScriptの重要性が再び見直されつつあります。
また、Node.jsの普及によって、JavaScriptがサーバーサイド言語としても進出してきていることから、バックエンドエンジニアであっても、JavaScriptをガッツリ書く機会が出てきている状況です。
そんな中で、JavaScriptに本来備わっているオブジェクト指向としての特性をフルに活かして、再利用性や保守性の高いコーディングを行うことが必要になってきています。
中には、
え!? JavaScriptってオブジェクト指向言語だったの!?
という方もいらっしゃるかも知れません。
そんな方は、JavaScriptのオブジェクト指向的な一面を知ると、きっと
「お前、意外とやるじゃねぇか!」
と、JavaScriptに対する印象を見直して頂けるものと確信しています 笑
まだ「オブジェクト指向」というのがどのようなものかよく分からない方は、事前に以下の記事に目を通しておくと、理解の助けになるかもしれません。
【初心者向け】オブジェクト指向とは >>
【オブジェクト指向の基本】クラス(class)とは >>
オブジェクト指向における「インスタンス」とは? >>
そもそもJavaScriptの使用経験があまりない方は、事前に以下の記事に目を通しておくと良いでしょう。
【初心者向け】JavaScriptって何? >>
JavaScriptからのDOM操作【初心者向けに基本から解説】>>
前置きが長くなりましたが、JavaScriptにおけるクラスのインスタンス生成について、学んでいきましょう!
JavaScriptのクラスについて
厳密に言うと、JavaScriptにクラスというものはありません。
代わりに、プロトタイプという呼び方をされます。
しかし、JavaScriptにおいても"class"キーワードを用いてプロトタイプを生成することもあり、ここでは便宜的にクラスという表現を使いましょう。
クラスとは、オブジェクトを生成する上での「設計図」のようなものだという説明が、オブジェクト指向の説明ではよく行われますね。
長ったらしく説明するよりも例を見た方が分かりやすいと思うので、以下の2つのボタンの例を見てみましょう。
2人の人間に対して、自己紹介をさせるボタンです。
試しに、それぞれ何回か押してみて下さい。
上記の機能は、以下のようなソースコードで実現されています。
(後ほど各項目の詳細を見ていくので、今はソースコードの内容を理解できなくても大丈夫です。)
<!--1つ目のボタン-->
<button onclick="human1.doSelfIntroduction();">
1人目の自己紹介
</button>
<!--2つ目のボタン-->
<button onclick="human2.doSelfIntroduction();">
2人目の自己紹介
</button>
<!--JavaScriptここから-->
<script>
//Humanクラスの定義 ここから-----
class Human {
//コンストラクター
//(newでHumanオブジェクトが作成された時に動くメソッド)
constructor(name, age) {
//名前を設定
this.name = name;
//年齢を設定
this.age = age;
//自己紹介の回数の初期値を設定
this.intro = 1;
}
//自己紹介を実施するメソッド
doSelfIntroduction(){
//自己紹介メッセージを表示
alert("私は" + this.name + ", "
+ this.age + "才です. "
+ this.intro + "回目の自己紹介です. ");
//自己紹介回数に1を加算
this.intro++;
}
}
//Humanクラスの定義 ここまで-----
//上記の定義を元に、Humanを2人作る
const human1 = new Human("太郎", 35);
const human2 = new Human("花子", 29);
</script>
<button onclick="human1.doSelfIntroduction();">
1人目の自己紹介
</button>
<!--2つ目のボタン-->
<button onclick="human2.doSelfIntroduction();">
2人目の自己紹介
</button>
<!--JavaScriptここから-->
<script>
//Humanクラスの定義 ここから-----
class Human {
//コンストラクター
//(newでHumanオブジェクトが作成された時に動くメソッド)
constructor(name, age) {
//名前を設定
this.name = name;
//年齢を設定
this.age = age;
//自己紹介の回数の初期値を設定
this.intro = 1;
}
//自己紹介を実施するメソッド
doSelfIntroduction(){
//自己紹介メッセージを表示
alert("私は" + this.name + ", "
+ this.age + "才です. "
+ this.intro + "回目の自己紹介です. ");
//自己紹介回数に1を加算
this.intro++;
}
}
//Humanクラスの定義 ここまで-----
//上記の定義を元に、Humanを2人作る
const human1 = new Human("太郎", 35);
const human2 = new Human("花子", 29);
</script>
既にオブジェクト指向プログラミングについてご存知の方であれば、上記のようなプログラムを見た際に、ピンとくる方が多いのではないでしょうか。
実際、私自身も、最初にJavaでオブジェクト指向を学んだ後にJavaScriptのオブジェクト指向について学んだので、上記のような記述がJavaScriptでもできることを知って、感動したことを覚えています。
念のため、上記のプログラムの流れを確認してみましょう。
- HTML上に2つのボタンを配置
- Humanクラスの定義を開始
- Humanクラスのコンストラクターを記述
- Humanクラスの自己紹介メソッドを記述
- 上記で定義したクラスを元に、インスタンスを生成
各項目について、詳細を見ていきましょう。
HTML上に2つのボタンを配置
まずは、HTML上に2つのボタンを配置しています。
以下の記述の部分ですね。
<!--1つ目のボタン-->
<button onclick="human1.doSelfIntroduction();">
1人目の自己紹介
</button>
<!--2つ目のボタン-->
<button onclick="human2.doSelfIntroduction();">
2人目の自己紹介
</button>
<button onclick="human1.doSelfIntroduction();">
1人目の自己紹介
</button>
<!--2つ目のボタン-->
<button onclick="human2.doSelfIntroduction();">
2人目の自己紹介
</button>
1つ目のボタンが押された時には、human1変数に格納されているオブジェクトのdoSelfIntroductionメソッドが、
2つ目のボタンが押された時には、human2変数に格納されているオブジェクトのdoSelfIntroductionメソッドが、
それぞれ呼び出されるようになっていますね。
Humanクラスの定義を開始
ここで、Humanクラスの定義を開始します。
いわば、「人間とはどういうものか」を記述した、設計図ですね。
以下のような記述から、クラスの定義が開始しています。
class Human {
classキーワードの直後にクラス名を記述することによって、Humanクラスの定義を行っています。
このHumanクラスには、以下で説明するような、「コンストラクター」と、「自己紹介メソッド」が用意されています。
Humanクラスのコンストラクターを記述
まずは、コンストラクターを作成します。
コンストラクターとは、設計図であるクラスからインスタンスが生成された時に動作する、特別なメソッドのことです。
このHumanクラスの例で言うと、その人の「名前」と、「年齢」、「自己紹介の回数」の初期値が設定されます。
ソースコードで言うと、以下の部分ですね。
constructor(name, age) {
//名前を設定
this.name = name;
//年齢を設定
this.age = age;
//自己紹介の回数の初期値を設定
this.intro = 1;
}
//名前を設定
this.name = name;
//年齢を設定
this.age = age;
//自己紹介の回数の初期値を設定
this.intro = 1;
}
「このインスタンスの」
という言葉に言い換えて下さい。
たとえば、「this.age = age;」であれば、
「このインスタンスの年齢は、ageである。」
と言い換えることができます。
引数として受け取ったageという値を、このインスタンスが持っているageという値に代入しているのですね。
thisは、「このインスタンスの」という意味だと覚えておくと良いと思います。
Humanクラスの自己紹介メソッドを記述
Humanクラスとは、いわば「人間の設計図」ですが、そこに
「人間が行う、自己紹介という動作の定義」
を記述することができます。
ソースコードで言うと、以下の部分ですね。
//自己紹介を実施するメソッド
doSelfIntroduction(){
//自己紹介メッセージを表示
alert("私は" + this.name + ", "
+ this.age + "才です. "
+ this.intro + "回目の自己紹介です. ");
//自己紹介回数に1を加算
this.intro++;
}
doSelfIntroduction(){
//自己紹介メッセージを表示
alert("私は" + this.name + ", "
+ this.age + "才です. "
+ this.intro + "回目の自己紹介です. ");
//自己紹介回数に1を加算
this.intro++;
}
そして、自己紹介を一回行うごとに、その人の自己紹介回数に、1が加算されます。
上記で定義したクラスを元に、オブジェクトを生成
以上でクラスの定義は終了したので、あとは、そのクラスを元に実際のオブジェクト、すなわちインスタンスを生成します。
ソースコードで言うと、以下の部分です。
//上記の定義を元に、Humanを2人作る
const human1 = new Human("太郎", 35);
const human2 = new Human("花子", 29);
const human1 = new Human("太郎", 35);
const human2 = new Human("花子", 29);
この記述によって、JavaScript上で、太郎さんと花子さんという2人の人間の実体が作成されました。
このhuman1という変数には、太郎さんのインスタンスが格納され、
human2という変数には、花子さんのインスタンスが格納されます。
ここで、constというキーワードが用いられていますね。
今はあまり気にする必要はないのですが、これは定数を定義するキーワードです。
定数とは、後から値を変えられない変数のことです。
代入したらそれっきりなのですね。
ただ、ここでhuman1やhuman2という定数に代入されているのは、「インスタンスの在りか」であることに注意してください。
何が言いたいかと言うと、そのインスタンスが持っているプロパティー値は変更が可能なのです。
たとえば、太郎さんの自己紹介回数は、太郎さんが1回自己紹介を行うごとに、増えていきますよね?
その部分は、定数ではありません。
あくまでこのconstは、human1が太郎さんのインスタンスを指している
という部分が固定されているだけであって、太郎さんが持っている個々の値は、変わる可能性があるのです。
今はあまり気にする必要はないのですが、これは定数を定義するキーワードです。
定数とは、後から値を変えられない変数のことです。
代入したらそれっきりなのですね。
ただ、ここでhuman1やhuman2という定数に代入されているのは、「インスタンスの在りか」であることに注意してください。
何が言いたいかと言うと、そのインスタンスが持っているプロパティー値は変更が可能なのです。
たとえば、太郎さんの自己紹介回数は、太郎さんが1回自己紹介を行うごとに、増えていきますよね?
その部分は、定数ではありません。
あくまでこのconstは、human1が太郎さんのインスタンスを指している
という部分が固定されているだけであって、太郎さんが持っている個々の値は、変わる可能性があるのです。
と、いうことで、
human1は太郎さんの
human2は花子さんの
インスタンスを指していることが分かりましたね。
ここで、もう一度、最初に記載したHTMLのボタンの定義を見てみましょう。
<!--1つ目のボタン-->
<button onclick="human1.doSelfIntroduction();">
1人目の自己紹介
</button>
<!--2つ目のボタン-->
<button onclick="human2.doSelfIntroduction();">
2人目の自己紹介
</button>
<button onclick="human1.doSelfIntroduction();">
1人目の自己紹介
</button>
<!--2つ目のボタン-->
<button onclick="human2.doSelfIntroduction();">
2人目の自己紹介
</button>
1つ目のボタンではhuman1の、2つ目のボタンでは、human2の自己紹介メソッドが呼び出されています。
最初にHTMLが読み込まれた直後に、その直下にあるJavaScriptもコンパイルされ、実行されていますから、ユーザーが画面上でこれらのボタンを押下する時点では、
既にhuman1という変数には、太郎さんのインスタンスが格納され、
human2という変数には、花子さんのインスタンスが格納されます。
その為、この2つのボタンは、それぞれ別々のHumanインスタンスに対して命令を行うことになります。
JavaScriptでオブジェクト指向を使うメリットとは?
上記の例では、JavaScript上でクラスを定義し、インスタンスを生成する例を見てきました。
しかし、このようなオブジェクト指向の性質を利用したプログラミングを行うことには、どのようなメリットがあるのでしょうか。
最も大きなメリットは、
直感的に分かりやすい
という点だと思います。
実は上記のような機能は、別にクラスだのインスタンスだの、オブジェクト指向の性質を用いなくても、手続き的に記述することもできます。
(手続き的とは、オブジェクト指向などを用いず、ただ単に処理を順番に書いていくことです。)
しかし、太郎さんと花子さんという2人の人がいて、それぞれが自己紹介を行った回数などを個別に管理する変数が、それぞれ必要になるわけですから、ちょっとめんどくさいですね。
また、名前、年齢というのは、一般的に管理される値と言うよりも、太郎さんとか花子さんとか、それぞれの「人に紐づいた値である」と考えるのが普通です。
- それぞれの人が名前を持っている
- それぞれの人が年齢を持っている
- それぞれの人が、自分が自己紹介した回数を覚えている
- それぞれの人が、自己紹介という動作を行うことができる
というような、極めて実世界の概念に近い形でプログラム上のデータを管理できるという点において、オブジェクト指向はとても優れています。
JavaScriptにおけるクラスの特徴
JavaScriptにおけるオブジェクト指向は、その他の言語と比べるといくつかの特徴があるのですが、上記の例から端的に分かる特徴は、以下のものではないでしょうか。
クラスの定義に、プロパティーがない
プロパティーとは何だったかと言うと、それぞれのインスタンスが持っている「データ」のことです。
この例で言うと、「名前」とか「年齢」とか「自己紹介の回数」に当たるものです。
JavaやPHPだと、クラスの定義の一番上に、
「このクラスが持てるプロパティーは、これとこれとこれだよ!」
という風に、明示的に並んでいるものです。
イメージで言うと、以下のような感じです。
//クラスにプロパティーを記述するイメージ
class Human {
var name;
var age;
var intro;
constructor(name, age) {
this.name = name;
this.age = age;
this.intro = 1;
}
class Human {
var name;
var age;
var intro;
constructor(name, age) {
this.name = name;
this.age = age;
this.intro = 1;
}
上記はあくまでイメージですが、Java等であれば、このようにあらかじめプロパティーをクラスの定義の中に列挙しておかないと、エラーが表示されてしまいます。
しかし、JavaScriptにおいては、上記のような記述は不要です。
(Rubyでも不要ですね。特にRubyではこういう風に書くと、「クラスインスタンス変数」という、何やらややこしい意味になってしまいます。。。)
JavaScriptにおいてこういった記述が不要なのには、JavaScriptのオブジェクトというものが、非常に柔軟に設計されていることが関係しています。
JavaScriptのクラスにおいては、プロパティーやメソッド自体を、インスタンス生成後でも自由に追加できるのです。
つまり、「this.name = name;」などと記述をすれば、その時点で、新しくnameというプロパティーを、インスタンスに対して追加できるのです。
JavaやPHP、VB.NETなどでオブジェクト指向を学んできた私としては、
「そんなのアリ!?」
と思うような機能でしたが、それができることによって、JavaScriptは非常に柔軟な機能を、実現できています。
まとめ:
JavaScriptクラスをオブジェクト指向的に記述して、
直感的に分かりやすいプログラミングをしよう!
如何でしたでしょうか?
JavaScriptでもクラスやインスタンスを用いて、オブジェクト指向的にプログラミングができそうな気がしてきましたでしょうか。
冒頭でも申し上げたように、厳密に言うと、JavaScriptにクラスというものはありません。
代わりに、プロトタイプという呼び方をされています。
この記事では、他言語との対比として分かりやすいように、クラスという言葉を用いさせて頂きました。
この機能を使いこなすことは、JavaScriptを用いてある程度の規模のプログラミングを行うときは必須となってきます。
JavaScriptは、中身をあまり分かっていなくても、ある程度動くものが作れる、初心者の方にもとっつきやすい言語だと思います。
しかし、整理された、高機能で無駄のないコーディングを行おうとすると、しっかりとした言語仕様の理解が必要になってきます。
JavaScriptを用いてクライアント側の機能を作成することに興味がある方は、ぜひJavaScriptにおけるオブジェクト指向について学んでみては如何でしょうか。
おすすめ書籍:
オブジェクト指向JavaScriptの原則
JavaScriptでオブジェクト指向を扱うことに興味が湧いたら、以下の書籍がおすすめです。
とても分かりやすく、JavaScriptにおけるオブジェクト指向について、書いてくれています。
いきなり難しい説明をすることなく、段階的に説明してくれているので、今はオブジェクト指向やJavaScriptの知識がない方でも、十分に理解できる内容だと思います。
また、全部で170ページと、そこまで分厚い本ではないので、苦しい思いをせずに読み切ることができます 笑
JavaScriptを書く機会がある方は、一回この本を読んでおくと、現場でのソースコードの書き方が大きく変わると思います。
この記事が、少しでも皆様のプログラミング学習の助けになれば幸いです。
最後まで読んで下さり、ありがとうございました。
0 件のコメント:
コメントを投稿