孤独プログラマー譚

孤独死が近い。

JavaScriptを超シンプルなMVCで書く(2)

以前の記事「JavaScriptを超シンプルなMVCで書く」を見返すとイマイチなので書き直し。
lonely-programmer.hatenablog.jp



以下挙動のアプリケーションを作ります。

・ボタンをクリックする毎に、白石麻衣の所属するグループが、乃木坂46 / 欅坂46 / SKE46 の順番でループする。



まずモデル。

var model = (function() {

    /* privateメンバ */
    var count = 0;
    var groups = [];
    // 現在のグループを取得
    var getNowGroup = function() {
      return groups[getIndex()];
    };
    // 現在のインデックスを取得
    var getIndex =  function() {
      // 0 → 1 → 2 → 0 → 1 → 2... とインデックスをループ
      return count % groups.length
    };

    /* publicメンバ */
    // グループを追加
    var addGroup =  function(group) {
      groups.push(group);
    };
    // グループを変更
    var changeHerGroup = function() {
      count++;
      $(this).trigger('groupIsChanged');
    };
    // グループ名を表示
    var getGroupName = function () {
      return getNowGroup().getName();
    };

    // publicメンバを開示
    return {
      addGroup: addGroup,
      changeHerGroup: changeHerGroup,
      getGroupName: getGroupName
    };

})();

モジュールパターンでオブジェクトを返却してます。
このオブジェクトはクロージャです。
privateメンバには外部からアクセスできません。



注目すべきはここ。

var changeHerGroup = function() {
  count++;
  $(this).trigger('groupIsChanged');
};

モデル内の値に変化があった場合、'groupIsChanged'イベントが発火されます。



オブジェクトではなく、コンストラクタ関数で返却する場合は、メソッド後半を以下のように書き変えます。

// コンストラクタ関数にpublicメンバを登録
var Constr = function() {
  this.addGroup = addGroup;
  this.changeHerGroup = changeHerGroup;
};
// プロトタイプにpublicメンバを登録
Constr.prototype = {
  getGroupName: getGroupName
};
// コンストラクタ関数を返却
return Constr;

 



グループ用のオブジェクトをモデルのプロパティに追加。
変数nameはprivateです。

// グループ用のコンストラクタ関数
function Group(name) {
  var name = name; // 書かなくても良い
  this.getName = function() {
    return name;
  };
}
// グループ追加
model.addGroup(new Group('乃木坂46'));
model.addGroup(new Group('欅坂46'));
model.addGroup(new Group('SKE48'));

 


ボタンがクリックされると、モデル内の値を更新。

// ボタンクリック時のイベントハンドラ
$('button').on('click', function() {
  model.changeHerGroup();
});

 


カスタムイベントを作成。

// レンダリング用カスタムイベント
$('span').on('render', function() {
  $(this).text(model.getGroupName());
});

 


モデル内の値に変化があれば、再レンダリングを行います。
jQueryのon()メソッドは、DOMオブジェクト以外も監視できることを最近知りました…。

// モデルを監視
$(model).on('groupIsChanged', function() {
  // テキストを再レンダリング
  $('span').trigger('render');
});

 


こちら、初期表示。

// テキストを初期表示
$('span').trigger('render');

// JavaScript処理完了後に画面表示
$('body').css('display', 'block');

 


ES6のことは一切考慮してません。笑
次回以降の記事で、ES6に書き換えてみようと思います。



以下、全コード。

<html>
<script src="jquery.js"></script>
<script>

$(function() {

  var model = (function() {

    /* privateメンバ */
    var count = 0;
    var groups = [];
    // 現在のグループを取得
    var getNowGroup = function() {
      return groups[getIndex()];
    };
    // 現在のインデックスを取得
    var getIndex =  function() {
      // 0 → 1 → 2 → 0 → 1 → 2... とインデックスをループ
      return count % groups.length
    };

    /* publicメンバ */
    // グループを追加
    var addGroup =  function(group) {
      groups.push(group);
    };
    // グループを変更
    var changeHerGroup = function() {
      count++;
      $(this).trigger('groupIsChanged');
    };
    // グループ名を表示
    var getGroupName = function () {
      return getNowGroup().getName();
    };

    // publicメンバを開示
    return {
      addGroup: addGroup,
      changeHerGroup: changeHerGroup,
      getGroupName: getGroupName
    };

  })();

  // Controller
  (function() {

    // グループ用のコンストラクタ関数
    function Group(name) {
      var name = name; // 書かなくても良い
      this.getName = function() {
        return name;
      };
    }
    // グループ追加
    model.addGroup(new Group('乃木坂46'));
    model.addGroup(new Group('欅坂46'));
    model.addGroup(new Group('SKE48'));

    // ボタンクリック時のイベントハンドラ
    $('button').on('click', function() {
      model.changeHerGroup();
    });

  })();

  // View
  (function() {

    // モデルを監視
    $(model).on('groupIsChanged', function() {
      // テキストを再レンダリング
      $('span').trigger('render');
    });

    // レンダリング用カスタムイベント
    $('span').on('render', function() {
        $(this).text(model.getGroupName());
    });

    // テキストを初期表示
    $('span').trigger('render');

    // JavaScript処理完了後に画面表示
    $('body').css('display', 'block');

  })();

});
</script>
<body style="display: none">
  <button>グループ変更</button>
  <p><span></span>の白石麻衣です。</p>
</body>
</html>