Help us understand the problem. What is going on with this article?

JavaScript初心者にclassを伝える

More than 1 year has passed since last update.

初めに

この記事ではJavascriptのclassについてザックリですが解説します。
多くの初心者にとってclassは「何だこれ???」と躓くポイントだと思います。
(実際、自分も最初眺めた時は意味が分からず頭が学級崩壊してました。)

なので、本記事ではサンプルコードと共に、
「何だこれ???」を「なるほど!!!」に
変えていけるように解説します。

序章 - 基本構文

まずはclassの基本構文を載せます。
使い方は後々に解説しますので、
とりあえず構文を眺めて美味しいご飯でも考えてください。
意味は深く考えないでいいと思います。

main.js
class NAME {
    constructor(a, b) {
        this.a = a;
        this.b = b;
    }
}

はいど~ん!
classの基本構文はこんな感じ!これだけ。

大丈夫です、内容も全く難しくないです。
解説すると、

・NAMEは任意の名前(変数や関数の定義と一緒)
・constructorは必須な関数(classが呼び出された時に最初に実行される関数)
・a, bの部分は任意の引数
 →constructorが最初に実行される関数なので、
  引数で初期値を受け渡したりします。
  また、引数の値を保持させるために、
  class自身(this)に保存します。

こういうことです。
これだけなんです。簡単ですね!

第一章 - 例を理解する

さて、構文が把握できた所で簡単な例文を載せます。
怖くないから怖じ気つかないでね。

main.js
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に保持する」処理しかしていません。

さて、本題は下の変数定義です。

main.js
let ball_a = new ball(0, 0, 10, 0);

これは何を意味しているのでしょうか?

これもまた簡単です。

これはball classの構造を持ったObjectを生成し、変数ball_aに格納する

ことを意味しています。

この「new演算子」とは、Objectを新しく作成する演算子です。
すなわち、この場合classと同じ役割を持った(構造を持った)新しいObjectを生成していることになります。
そして、生成したObjectを変数に代入している、それだけです。

分かりにくいですか?
大丈夫です。簡単です。

試しに

main.js
console.log(ball_a.dx);

こちらを実行するとどうなるでしょうか。
答えは簡単で10(dxの値)がconsoleに表示されます。

なぜなら、変数ball_aには(x, y, dx, dy) = (0, 0, 10, 0)
値を保持したObjectが格納されているからです。

分かりやすく書き換えるとこういう事です。

main.js
// コード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を使わない実装方法をお見せします。

main.js
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体の敵を実装しています。
そして、これにあるものを付け足してみます。

main.js
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に置き換えるとどうなるの?
って話ですが、こうなります。

main.js
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を使う時は…

main.js
class NAME {
    // constructorは必須
    constructor(/* 引数 */) {
        /* todo */
    }

    func_name (/* 引数 */) {
        /* todo */
    }

    /* and more function */
}

let a = new NAME(/* 初期値(パラメータ) */); // 新しくNAMEを作成して変数に代入

このようにして書く!
それだけ、です。
ネ。

終わり

最後まで読んでくださった方ありがとうございます。
文章をまとめるのが下手でグチャグチャした内容、
飛躍した箇所が数多くあったと思います。
分かりにくくて申し訳ないです。

何かご不明な箇所がありましたら、
気軽に質問してください。

それではまた。

(Qiita初投稿)

nnn-school
IT×グローバル社会を生き抜く“創造力”を身につけ、世界で活躍する人材を育成する。
https://nnn.ed.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away