JavaScriptの常識シリーズ第7弾。
クラス、コンストラクタ、インスタンス。
葬送のフリーレンを読んでいるとわかりやすいかもです。
読んでなくてもわかりやすいとおもいます。
html-css-javascript.hatenadiary.com
この記事ですでに実践しているんですけど、ここで一つ切り取って、記事としてしまいます。
理解できれば別に大したものではないんですけど、理解するまでが大変です。
もう名前からして中ボス感満載な感じがします。
まあでもいうほど難しいものではなく、簡単に言ってしまえば、クラスは設計図、インスタンスはその設計図を見て実際に作ったものです。
で、コンストラクトは・・・。
わかるかボケ。
設計図?
文字列ばっかりが並んだうちのどれが設計図だよ。
というわけで私なりの解説をします。
これを完全に説明するとなると、ものっすごい基礎のところをもっかい書いていくことになるのですが、まあこの際です。
そういうのも全部書いていきましょう。
まず基本中の基本、オブジェクトです。
オブジェクトとは
これは箱みたいなものです。
箱にはいろんな種類があります。
たとえばハンマーを取り出したいとします。
道具箱、工具箱、文房具箱、跳び箱(?)、と箱にもいろいろありますが、この場合取り出すのは工具箱です。
なので例えばハンマーを取り出したかったら、「ハンマーを工具箱というオブジェクト」から取り出すという感覚です。
これがカッターナイフがほしいとしたら「文房具箱というオブジェクト」から取り出します。
んで、このハンマーとかカッターナイフがメンバもしくは要素と呼ばれます。
(メンバはあまり使われなくなってきた言葉だそうですが、便利なので私は勝手に使ってます。)
で、このメンバ、ただモノの名前をオブジェクトの箱に入れるだけでなく、なんと「ハンマーで打つ」という動作そのものもメンバにできてしまいます。
つまり以下のような感じです。
工具箱の中身=[ハンマー、レンチ、ペンチ、打つ、回す、挟む]
こういった感じで、モノと動作を同じように同等のものとして入れることができます。
で、モノのことをプロパティ、動作のことを関数と呼びます。
で、呼び出し方は、箱であるところの「オブジェクト.(←こいつ)プロパティ、もしくは関数」、という具合にドットで区切ります。
もちろん工具箱の中にまた小さな箱があって、その中にある釘を取り出したいなら、「オブジェクト.小さな箱.釘」のように書きます。
工具箱.小さな箱.釘;
オブジェクト、プロパティはこんな具合です。
動作を表す関数だったら、()が最後に必要になるので、「工具箱.ハンマー.ハンマーで打つ()」
工具箱.ハンマー.打つ();
こんな感じです。
これをちょっとそれっぽくするために、工具箱はtoolBox、ハンマーはhammer、打つをhit()とでもしておきましょう。
あとこれだけだと寂しいのでレンチも入れておきましょうか。
レンチはwrench、レンチは回すものだからturn()がいいですね。
toolBox.hammer.hit(); toolBox.wrench.turn();
これで「工具箱からハンマーを取り出して打つ」「工具箱からレンチを取り出して回す」です。
嘘か本当か、かの本田宗一郎はミスをした部下にレンチを回すんじゃなくてぶん投げたそうです。
さて本番。
クラス、コンストラクタとは
まず順番的にコンストラクタを先に説明した方がいいのでそうします。
コンストラクタってのは作る人です。
今回の場合で言えば工具箱を作る人です。
次にクラスってのは同じ種類でまとめたモノです。
クラスチェンジって言葉を考えるとわかりやすいと思います。
一つの種類から別の種類にチェンジするときに使う言葉です。
今回で言うならハンマーとレンチが入った工具箱という種類で統一されていますよね。
というわけで、やることは工具箱を作る人が、同じ種類の工具箱を作るということです。
この同じ種類ってのが結構クセモノな気がしますけど、要は「同じ工具箱」「同じ種類の中身」を作るということです。
なんで「同じ種類の中身」という言い方なのかというと、同じ種類であれば数が違ってもいいからです。
これを実際に書くとこんな感じ。
class 工具箱 { constructor(ハンマー, レンチ) { this.ハンマー = ハンマー; this.レンチ = レンチ; } 打つ() {} //セミコロンは要りません 回す() {} }
上述の通り、同じ種類の工具箱を作ります。
つまり、中にハンマーとレンチが入ってる工具箱です。
同じ種類だから上で言ったようにクラスを使います。
で、作る人であるところのコンストラクタさんの中にハンマーとレンチを入れているわけです。
ちなみに、ここで出てくるthisについては、JavaScriptの常識シリーズ③で解説しています。
html-css-javascript.hatenadiary.com
コンストラクタの引数は内容が増えるにしたがって増えていきます。
ペンチも入れたかったら、以下のようになります。
class 工具箱 { constructor(ハンマー, レンチ, ペンチ) { this.ハンマー = ハンマー; this.レンチ = レンチ; this.ペンチ = ペンチ; } 打つ() { } 回す() { } 挟む() { } }
ちゃんとJavaScript風に書くと
class toolBox { constructor(hammer, wrench, pliers) { this.hammer = hammer; this.wrench = wrench; this.pliers = pliers; } hit() { } turn() { } pinch() { } }
なお、コンストラクタはconstructorのみです。
これはあらかじめJavaScriptで予約された言葉なので、他の言葉を使ってもコンストラクタの役目は果たしてはくれません。
さてもう一度コードをみると、ここで不思議なことが起こっています。
打つ、回す、挟むといった動作、すなわち関数がなぜコンストラクタの中に含まれていないのでしょうか。
これは共通するものだからです。
どのハンマーでも「打つ」し、どんなレンチでも「回す」し、どんなペンチも「挟」みます。
注意すべきは、この段階では「ハンマーが打つ」という風にはくくられていません。
人間にとっては当然でも、JavaScriptには「打つのはハンマーだ」ということはわからないのです。
「こういうもの(プロパティ)が入っていて、こういう動作(関数)も入っている」ことだけが定義されただけです。
それらの紐づけはあとでやることにします。
(スクロールしていけば見出しに出してるのでわかります。)
まずはこれでクラスは出来上がりました。
コンストラクタの意味もわかりました。
次にインスタンスです。
インスタンスとは
先ほど書いたコンストラクタ。
じつは書いただけではただの文字です。
とある呪文を唱える必要があります。
それはゾルトラークnewです。
これで初めてコンストラクタさん、つまり作る人が工具箱を作ってくれます。
書き方は以下の通り。
const フリーレンの工具箱 = new 工具箱(3,2,1);// ハンマー3本、レンチ2本、ペンチ1個
これ、実をいうとオブジェクト化です。
だってフリーレンの工具箱だし。
中身がないとおかしいし。
じゃあ右辺では何をやってるのかというと、コンストラクタさんが左からハンマーを3本、レンチを2本、ペンチを1個入れた工具箱を作ってくれたわけです。
そう。
やってくれたのはコンストラクタさん。
なのにこのクラスであるところの工具箱がやったみたいに見せかけているんです。
コンストラクタさんにしてみれば、手柄を横取りされたような気分です。
でもこれ、よくみるとnew 工具箱がフリーレンの工具箱って、すごく「フリーレンが新しい工具箱を手に入れた」って感じになりません?
魔導書じゃないのは・・・あれです、フリーレンは依頼で工具箱を探すことになって、見つけたので一時的にフリーレンの所有物になったんです。
で、同じようにどんどん作れます。
const フェルンの工具箱 = new 工具箱(8,1,1); const シュタルクの工具箱 = new 工具箱(3,2,1);
みんなおニューの工具箱を手に入れています。
誰かを殴るためか、ハンマーが多めに入ってるのを選んだ人もいますが。
とにかく。
フリーレン御一行様は全員おニューの工具箱を手に入れて、その中身も示されているわけです。
完全にオブジェクト化されたわけです。
で、このオブジェクト化されたオブジェクトのことをインスタンスと呼ぶんです。
つまりフリーレン御一行様が持っている工具箱はすべてインスタンスです。
まあここまで読めば、今まで読んできた設計図云々がどれにあたるのかということもわかるかと思います。
設計図を基に同じものをいくらでもつくれる、というのもピンとくるものがあると思います。
最後にこれをそれっぽくするために、日本語を英語にしておきましょう。
const FrierenToolBox = new toolBox(3, 2, 1); const FernToolBox = new toolBox(8, 1, 1); const StarkToolBox = new toolBox(3, 2, 1);
もうこれで、誰の工具箱に何がどれだけ入ってるかも明らかになりました。
関数の呼び出し
上述のとおり、レンチは投げるんじゃなくて回すものだという社会の常識はJavaScriptは理解していません。
なので、レンチは回すものだと教えなければなりません。
でもそれはむずかしくありません。
.で結べばいいだけです。
StarkToolBox.wrench.turn();
終了。
というか、どっかですでに書いたような気もしますが、まあいいでしょう。
組み込みオブジェクト
ここまでクラスを定義してコンストラクタによってインスタンスをつくる、ということをやってきました。
もう意味不明に見えたこの文章もわかることと思います。
で、ここでひとつ注意したいことがあります。
おそらくこの先、あるいはここに至るまでにこういう感じのやつを見たことがあると思います。
const date = new Date();
こういう風に書いてるくせに、Dateなんてクラスは定義されているところはなかったはずです。
なぜならこれはすでにJavaScriptが用意してくれているクラス(正確には組み込みコンストラクタ)だからです。
こうしたクラスで作られるオブジェクトを組み込みオブジェクトといいます。
逆に言えば、Dateという言葉でクラスを定義してしまうと、本来の意味が上書きされてしまいます。
そんなもん、ここで全部覚えられるわけがありません。
じゃあどうやって回避するのかというと、オリジナリティあふれる言葉を使うようにします。
たとえばDateだったらやばいけど、toolBoxDateだったらさすがに被らないでしょう。
こんな風に被らない言葉、オリジナリティあふれる言葉をつかって回避しましょう。
ちなみにDateに関しては、ここでわかります。
html-css-javascript.hatenadiary.com
終わりに
これで、今度こそクラス、コンストラクタ、インスタンスの意味は理解できたと思います。
まさかこれだけでここまで長くなるとは思いませんでしたが、理解するためということを考えたら無駄ではなかったように思います。
また「俺、やっぱりわかってないよな」というところがあったらJavaScriptの常識シリーズを書いていきます。