初めに
この記事ではJavascriptのclassについてザックリですが解説します。
多くの初心者にとってclassは「何だこれ???」と躓くポイントだと思います。
(実際、自分も最初眺めた時は意味が分からず頭が学級崩壊してました。)
なので、本記事ではサンプルコードと共に、
「何だこれ???」を「なるほど!!!」に
変えていけるように解説します。
序章 - 基本構文
まずはclassの基本構文を載せます。
使い方は後々に解説しますので、
とりあえず構文を眺めて美味しいご飯でも考えてください。
意味は深く考えないでいいと思います。
class NAME {
constructor(a, b) {
this.a = a;
this.b = b;
}
}
はいど~ん!
classの基本構文はこんな感じ!これだけ。
大丈夫です、内容も全く難しくないです。
解説すると、
・NAMEは任意の名前(変数や関数の定義と一緒)
・constructorは必須な関数(classが呼び出された時に最初に実行される関数)
・a, bの部分は任意の引数
→constructorが最初に実行される関数なので、
引数で初期値を受け渡したりします。
また、引数の値を保持させるために、
class自身(this)に保存します。
こういうことです。
これだけなんです。簡単ですね!
第一章 - 例を理解する
さて、構文が把握できた所で簡単な例文を載せます。
怖くないから怖じ気つかないでね。
class ball {
constructor(x, y, dx, dy) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
}
let ball_a = new ball(0, 0, 10, 0);
はい。
大丈夫です!簡単です!解説します!
まずclassの中身を見ていきます。
すごく単純です。
引数にはx, y, dx, dy
がありますね。
そして、それら全てはthisに保存しています。
はい、classの中身はたったこれだけです。
「引数をthisに保持する」処理しかしていません。
さて、本題は下の変数定義です。
let ball_a = new ball(0, 0, 10, 0);
これは何を意味しているのでしょうか?
これもまた簡単です。
これはball class
の構造を持ったObject
を生成し、変数ball_a
に格納する
ことを意味しています。
この「new演算子」とは、Objectを新しく作成する演算子です。
すなわち、この場合classと同じ役割を持った(構造を持った)新しいObjectを生成していることになります。
そして、生成したObjectを変数に代入している、それだけです。
分かりにくいですか?
大丈夫です。簡単です。
試しに
console.log(ball_a.dx);
こちらを実行するとどうなるでしょうか。
答えは簡単で10(dxの値)がconsoleに表示されます。
なぜなら、変数ball_a
には(x, y, dx, dy) = (0, 0, 10, 0)
の
値を保持したObjectが格納されているからです。
分かりやすく書き換えるとこういう事です。
// コードA
let ball_a = {
x: 0,
y: 0,
dx: 10,
dy: 0
};
// コードB
let ball_a = new ball(0, 0, 10, 0);
// コードAとコードBは一緒な処理をしている
こういう事なんですよね。
どうでしょうか、簡単ですよね。
classはこういったObjectの構造を単純化出来て、
一つ定義してあげれば何回でも、同じ構造のObjectが簡単に作れるよ~って事ですね。
例えばめちゃくちゃ複雑なObjectを定義した場合、
毎回毎回、ブラケッツ( {と}
)で囲んで記述すると、
可読性が落ちて、デバッグのコストが大変なことになります。
そんな時はObjectの構造体をclassを定義して、
使用時はnew演算子で定義するほうが楽ですよね。
そうすることによってコードの質も高くなります。
第二章 - ちょっと複雑なもの
恐らく、序章と第一章で全体像を何とな~~く理解できたと思うので、
第二章では実用例を上げながら解説していきます。
ここでの題材は、「シューティングゲームにおける敵の出現の実装」です。
敵を作りたいです。
もちろん、たくさんの敵を。
シューティングゲームを作る際には、
敵を沢山出現させたいですよね。
そんな時にclassはもってこいの存在です。
まず、最初に敵の構造を考えます。
・HPがある
・座標 (x, y) がある
・移動速度 (dx, dy) がある。
これらが敵の構成だとします。
ここまで出来たら次のステップ。実装です。
が、まず最初はあえてclassを使わない実装方法をお見せします。
let enemies = []; // 敵を格納する配列
enemies[0] = {
x: 0,
y: 0,
dx: 2,
dy: 0,
hp: 50
};
enemies[1] = {
x: 10,
y: 0,
dx: 0,
dy: 2,
hp: 100
};
こんな形で実装したとします。
ここでは2体の敵を実装しています。
そして、これにあるものを付け足してみます。
let enemies = []; // 敵を格納する配列
enemies[0] = {
x: 0,
y: 0,
dx: 2,
dy: 0,
hp: 50,
move: function() {
this.x += this.dx;
this.y += this.dy;
}
};
enemies[1] = {
x: 10,
y: 0,
dx: 0,
dy: 2,
hp: 100,
move: function() {
this.x += this.dx;
this.y += this.dy;
}
};
移動をする関数を実装して追記しました。
はい、何か気がついたことはありませんか?
いいですか、私はあなたに点を投げかけますからね?
点と点をつないで線にするのはあなた方次第ですからね?
もしこのまんま、敵が10体、50体...と大量に必要になったらどうでしょうか。
毎回、同じ構造のObjectにもかかわらず、同じコードを大量に書くことになります。
そして100体の処理を定義した後に、構造を変えたいとなったならば、
該当箇所をすべて変更しなければいけないということに陥ります。
悲惨ですね。面倒くさいですね。嫌ですね。
マンネリな人間にはなりたくないですね。
じゃあどうすればいいんですか!!!!って怒る前に聞いてください。
あなたにはclassのご加護がありますよ。
classは全てを解決します。
すなわちclassは救世主。
じゃあclassに置き換えるとどうなるの?
って話ですが、こうなります。
class enemy {
constructor(x, y, dx, dy, hp) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this.hp = hp;
}
move() {
this.x += this.dx;
this.y += this.dy;
}
}
let enemies = []; // 敵を格納する配列
enemies[0] = new enemy(0, 0, 2, 0, 50);
enemies[1] = new enemy(10, 0, 0, 2, 100);
はいqiita━━━━(゚∀゚)━━━━!!
めちゃくちゃシンプルで見やすくなりましたね!
これなら敵が増えてきても、楽ですね。
構造を変えたい!ってなったらclassの中身を弄るだけで済みます。
こうすることで可読性も向上し、デバッグのコストもめちゃくちゃ良くなります。
これが実例をもとに説明するclassを利用するメリットですね。
classを用いると、複雑な構造になったObjectであっても、またそれが
複数利用していようが、一箇所変更するだけで変更できちゃうわけですね。
まとめ
classというのは…
・同じ構造を持ったObjectを複数使用したい時に使う!
つまり…
・複雑なObjectでも誰でも、簡単!一括管理できる!
すると…
・簡略化出来て可読性が上がる!
・デバッグのコストが減る!
・気持ちいい!
というものです!
classを使う時は…
class NAME {
// constructorは必須
constructor(/* 引数 */) {
/* todo */
}
func_name (/* 引数 */) {
/* todo */
}
/* and more function */
}
let a = new NAME(/* 初期値(パラメータ) */); // 新しくNAMEを作成して変数に代入
このようにして書く!
それだけ、です。
ネ。
終わり
最後まで読んでくださった方ありがとうございます。
文章をまとめるのが下手でグチャグチャした内容、
飛躍した箇所が数多くあったと思います。
分かりにくくて申し訳ないです。
何かご不明な箇所がありましたら、
気軽に質問してください。
それではまた。
(Qiita初投稿)