【JavaScript】じゃんけん関数を”class”で定義する(constructor, getter, setterなど)

プログラミング初心者の勉強ブログ #115

じゃんけんのアルゴリズムが課題で出され、せっかくの機会なので現代的?と言われるJavaScriptの書き方で書いてみることにした。プロパティとメソッドとか変数とか関数とか、Rubyともごっちゃになり概念とか呼び方の若干の違いに戸惑いつつ、できるだけ整ったコードを書いていく。

 

目次

[toc]

 

じゃんけんアルゴリズム

じゃんけんアルゴリズムも色々あると思うが、今回は、

じゃんけんアルゴリズムをちょっと応用 – Qiita

ここのを使ってみる。(検索結果1位だったやつ)

じゃんけんアルゴリズム

 

先に完成コードを載せる

getElementとaddEventはjQuery。

 

index.html

<body>
  <main>
    <ul>
      <li id="gu_btn" value="0">グー</li>
      <li id="cho_btn" value="1">チョキ</li>
      <li id="par_btn" value="2">パー</li>
    </ul>
    <div>コンピュータの出した手: <span id="pc_hands"></span></div>
    <div id="judgment"></div>
  </main>
  <script src="./js/janken.js"></script>
</body>

 

janken.js

// クラス定義
class Janken {
  // 初期化
  constructor() {
    const gu = $('#gu_btn');
    const cho = $('#cho_btn');
    const par = $('#par_btn');
    this.judgment = $('#judgment');
    this.pc_hands = $('#pc_hands');
    this.hands = {
      0: 'グー',
      1: 'チョキ',
      2: 'パー'
    }
    this.results = {
      0: 'あいこ',
      1: 'まけ',
      2: 'かち'
    };
    this.btnArray = [gu, cho, par];
  }

  // ゲッターにする必要性は全くない。試しにgetterを使ってみただけ。
  get init() {
    this.setEvent();
  }

  // イベントリスナー定義
  setEvent() {
    this.btnArray.forEach(btn => {
      btn.on('click', (e) => {
        const userHands = Number(e.target.attributes.value.value);
        const pcHands = this.setPcHands();
        const result = this.battle(userHands, pcHands);
        this.renderPcHands(pcHands);
        this.renderResult(result);
      });
    });
  }

 // PCの手を0, 1, 2からランダムに決める。
  setPcHands() {
    return Math.floor(Math.random() * 3);
  }

  // じゃんけんの勝敗を決める。(先ほどのアルゴリズムより)
  battle(userHands, pcHands) {
    const num = (userHands - pcHands + 3) % 3;
    return this.results[num];
  }

  // PCの手を表示
  renderPcHands(pcHands) {
    this.pc_hands.html(this.hands[pcHands]);
  }

  // 勝敗の表示
  renderResult(result) {
    this.judgment.html(result);
  };
};

// 即時関数
(() => {
  'use strict';
  
  // オブジェクト生成(このときconstructor()が自動実行)
  const janken = new Janken();

  // ゲッター呼び出し(プロパティと同じ呼び出し方)
  janken.init;
})();

 

ポイント

自分の中での学びのポイントを列挙。

 

じゃんけんの勝敗を決めるアルゴリズムは正味1行

色々取っ払って考えると、

const num = (userHands - pcHands + 3) % 3;

この「num」が定義される瞬間に勝敗が決まる。

results = {
  0: 'あいこ',
  1: 'まけ',
  2: 'かち'
};

results[num]

numの数値を配列やハッシュで文字列と紐付け変換すれば、if文を使うことなく表示までの流れを行うことができる。

 

constructor

JSでクラスを定義したときの初期化メソッド名。Rubyで言うinitializer。constructor内に定義した内容は、インスタンス生成時に自動実行される。特にこっちで関数を呼び出す必要はなくなる。

// オブジェクト生成(このときconstructor()が自動実行)
const janken = new Janken();

 

getter / setter

JSのクラス定義をMDNとかで調べていると、ゲッターやらセッターなど出てきてよくわからなかったので、一応調べて確認した。とりあえずgetterは「見た目はプロパティ、中身は関数」的なもの。プロパティを呼び出すと、そのプロパティと紐づいた関数を実行してくれる。このgetterともう一つ「setter」と呼ばれるものが存在するが、この2つは「アクセサプロパティ」と呼ばれ、オブジェクト外からの関数に対してのアクセスを許す仕組みである。Rubyで言うattr_accessor的な。

今回の場合、

  // ゲッターにする必要性は全くない。試しにgetterを使ってみただけ。
  get init() {
    this.setEvent();
  }

「init」を意味もなくゲッターとして定義している。この場合、

// ゲッター呼び出し(プロパティと同じ呼び出し方)
janken.init;

上のようにinitを呼び出すが、もしこれがgetter出なかった場合は普通の関数なので

janken.init();

()をつける関数の呼び出しを行う必要がある。見た目はプロパティ。本来のゲッターとセッターの使用目的は外部からのアクセスや変数の書き換えなので、正直ここら辺のカッコがついてるとかついてないとかの話は重要ではない。

JavaScript で setter/getter – あどけない話

アクセサプロパティ(getterとsetter) – 30歳からのプログラミング

この2つとMDNを参考にした。また、

結局のところgetter/setterは要るのか?要らないのか? – Qiita

そもそも要るのか要らないのかとかなっている。確かにRubyでもあまりアクセッサーは使わなかった。

 

まとめ

JSの基礎的な部分が所々抜け落ちている。どっかのタイミングでゲッターとか習っていたのかもしれないが、全く覚えていなかった。「Rubyで言う〜」という流れで別言語の謎概念もなんとなく理解ができるようになっているのが助かる。

ジーズアカデミーでの課題提出は、提出後必ずみんなの前で発表する形式である。それが同期との競争心を生みだしていると思う。いかにあっと言わせられるプロダクトを同期の前で発表するか。僕もここに焦点がいく。「あっと言わせる」度数は、プロジェクターでプロダクトの画面を表示させながら発表する関係もあり、フロントでの動きがイケてるととても目立つ。もちろん機能面で、どうやって実装しているんだこれは、という点もスゴさを感じるが、比較して、生のコードの綺麗さ、コーディングの洗練具合にはあまり焦点がいかなくなってしまう。今回はそこを補完していく取り組みである。

幸いにも綺麗なコードを書くことに対する美学はここ2〜3ヶ月ほど前から自分の中に着々と育まれており、(特にSassとBEM、ドットインストールのJSをやったあたりから)嫌いだったリファクタリングも最近はモチベーションを保つことができる。

現代JSの書き方を見様見真似でやっていると、jQueryを使わない書き方をしたくなってしまう。jQueryの方がDOM要素の取得やイベントリスナーなどのコード長が圧倒的に少ないのにも関わらず、わざわざ素のJSで「document.getElement〜」とか書きたくなってしまう。jQueryとJSを混ぜて書く気持ち悪さの方がめんどくささより勝る現象。とは言いつつ、最近はあまり抵抗なく混ぜて書いてる。jQueryとJSで若干のオブジェクトの構造に違いがあるのが難点。

じゃんけんの課題、フロントどうするか迷い中。王道のサザエさん風か、もしくはJSプラグインにしてやろうかなと思っている。CDNにして誰でも使えるようにしたら面白そう。できるかわからんが、レベル感的にそんくらいしないとインパクトで他に負けてしまいそう。

以上ありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA