JavaScriptパターン 第5章

最後に読んだのいつだったかなーと思ったら4ヶ月前とか……
JavaScriptをがんばる年だったのにいつの間にか脱線。いつもの悪い癖。

名前空間パターン

function Constructor1() {}
function Constructor2() {}
var aaa = {};
var bbb = {};

とかやってしまうとグローバルを汚染しまくりなので、
ひとつのグローバルオブジェクトに追加しましょう。

var Global = {};
Global.Constructor1 = function() {};
Global.Constructor2 = function() {};
Global.aaa = {};
Global.bbb = {};

汎用の名前空間関数

上記のコードだと、既にGlobalが定義されていた場合、
上書きしてしまうので少し工夫をします。

var Global = Global || {};

Global以下に作成するコンストラクタやクラスがない場合はこれでもいいですが
多くなってきた場合、とても大変なので汎用の名前空間関数を作成すると便利です。

var Global = Global || {};
Global.namespace = function(ns) {
  var parts = ns.split('.');
  var parent = Global;
  // 先頭がGlobalで始まっていたら取り除く
  if (parts[0] === 'Global') {
    parts = parts.slice(1);
  }
  for (var i = 0, len = parts.length; i < len; i++) {
    // プロパティがなかったら作る
    if (typeof parent[parts[i]] === 'undefined') {
      parent[parts[i]] = {};
    }
    parent = parent[parts[i]];
  }
  return parent;
};
var hello = Global.namespace('Global.hello.world');
hello === Global.hello.world;  // true
var util = Global.namespace('util.special');
util === Global.util.special;  // true

プライベートメンバ

クロージャで隠しましょう。

function Aaa() {
  var name = 'aaa';
  this.getName() = function() {
    return name;
  };
}
var a = new Aaa();
a.name;       // undefined
a.getName();  // 'aaa'

プライバシーの侵犯

クロージャで隠してもオブジェクトの場合、参照できてしまう……

function Aaa() {
  var struct = {
    a: 1,
    b: 2,
    c: 3
  };
  this.getStruct = function() {
    return struct;
  };
}
var a = new Aaa();
var s = a.getStruct();
s.a = 100;
s.b = 200;
a.getStruct();  // { a: 100, b: 200, c: 3 }

オブジェクトで返さない、もしくはディープコピーする、などですかねえ。

オブジェクトリテラルとプライバシー

var obj = (function(){
  var name = 'obj';
  return {
    getName: function() {
      return name;
    }
  };
}());
obj.getName();  // 'obj'

モジュールパターンって呼ぶみたい。

プロトタイプとプライバシー

コンストラクタを使ってprivateを実現すると、オブジェクトを作成するたびにプライベートメンバが作成される。
なので、クラスで共通なメンバはprototypeに追加しましょう、とかなんとか。

function Aaa() {
  var name = 'aaa';
  this.getName = function() {
    return name;
  };
}
Aaa.prototype = (function(){
  var title = 'bbb';  // private
  return {
    // public
    getTitle: function() {
      return title;
    }
  };
}());
var aaa = new Aaa();
aaa.getName();   // 'aaa'
aaa.getTitle();  // 'bbb'


今日はここまで。重要なところだなー。