じょりじょり日記

JavaScript100サイトチャレンジを記録するブログです。

デザインパターンにおけるオブザーバの解釈 | JavaScriptチャレンジ11日目

JavaScriptデザインパターンのうちの最もよく使われるオブザーバについて、自分の解釈が合っているかどうか確認する意味も込めて、コメントを振りました。
今回からチャレンジの趣旨を1つのコンポーネント作成から「JavaScriptの根底を理解する」に方針転換しています。
コードと向き合うとはどういうことなのか、自問自答した結果、それが必ずしも目に見えなくてもよいという結論に至り、今回のような形もどんどん載せていきたいと思います。もっと自分で出来ることがあるとおもっているので、JavaScriptの表面をなぞるようなことを100回通してするのではなく、もっと難しいコードを理解していきたいです。

技術力育成につき、お見苦しいとは思いますが、お付き合いいただければ幸いです!(^o^)

最近やっと(function() {})(); という即時関数の書き方に慣れてきました。
そういえば、なぜ即時関数って必要なんでしょうか。すぐに実行したいからでしょうか。
調べてみると、即時関数を使う理由は、関数を定義するとともに即実行したいからとは別に、もう一つ大きな理由がありました。

それはスコープ(変数の生きられる領域)の範囲を狭めて、疎結合なコードを書くという目的もあるようです。
すべてをグローバル変数で定義してしまうことはアンチパターンらしく、たしかにこんがらがりやすそうだなと感じました。

さて、では名前付き変数は何故存在するのかという疑問に当たりました。
調べてみると、関数名を定義することで何度も呼び出せる = 再利用性に富んだコードになるようです。
確かにさきほど、ドットインストールのストップウォッチを作るというJavaScriptコースを観ていたのですが、booleanと関数を組み合わせて、クラスの追加・削除を条件分岐で表現していて、なるほど、再利用性!とおもったのでした。


// コンストラクタの生成
function Observer() {
  // 監視者を格納するための空のオブジェクト
  // 何故オブジェクトか?→複数管理したい
  this.listeners = {};
}
// listenersというHashの中にArrayがあって
// lisnerts[event] //indexNumbering
// これがvalueになるとして、keyは・・・。
// listeners = { key => listeners[event] }


// what's on...?
// this.listenersにイベントを通知したい関数を追加するメソッド
Observer.prototype.on = function(event, func) {
  // listenersにイベントが存在しなかった場合、配列を作成
  if (! this.listeners[event]) {
    this.listeners[event] = [];
  }
  // あった場合は追加する
  this.listeners[event].push(func);
};

// what's off...?
// 指定されたオブザーバーを検索し削除するメソッド
Observer.prototype.off = function(event, func) {
  // このrefはlistenersにあるeventを参照していて
  // for文で繰り返す要素数を特定するために参照している
  var ref = this.listeners[event],
      len = ref.length;
  for (var i = 0; i < len; i++) {
    var listener = ref[i];
    if (listener === func) {
      ref.splice(i, 1);
    }
  }
};

// what's trigger...?
// オブザーバーのリスト全体を反復処理し実行するメソッド
Observer.prototype.trigger = function(event) {
  var ref = this.listeners[event];
  for (var i = 0, len = ref.length; i < len; i++) {
    var listener = ref[i];
    if(typeof listener === "function") listener();
  }
};

// オブザーバーのインスタンスを生成する
var observer = new Observer();
// greetという変数を定義し、呼ばれた時にGood morningを呼ぶ
var greet = function() {
  console.log("Good morning");
};
observer.on("morning", greet);
observer.trigger("morning");
// =>Good morning

var pen = function() {
  console.log("I am a pen");
}
observer.on("penintro", pen);
observer.trigger("penintro");
// => I am a pen