All Articles

アプリケーション内の設定情報を固定化する方法について

やってる人はやってるだろうけど、ちょっと使えるかもしれない手法。僕はよくやりますが。 ちなみに、ブラウザのクライアントサイドのケースです。Node.jsはそもそも問題がありません。

グローバル(じゃなくてもいいけど)な設定情報の取り込みと固定化

最近のJavaScriptのアプリケーションはどんどん複雑化してる感じで、その中でアプリケーションの動作方法を設定に記述して、その値を元に動作を決めたりすることが僕はよくあります。

というか、複数人で違う環境でやるとき、この設定をそれぞれ編集すればOKみたいな感じにすることが多いです。サーバーサイドでもそうですよね。

で、window.Configに設定オブジェクトを作って、アプリケーションから参照できるようにしたりするんですが、グローバルなオブジェクトだと、アプリケーション動作中に外部から変更がかけられたりして怖いですね。例えば、以下の場合。

// 設定オブジェクト(別ファイルにして結合することの方が多い)
Config = {
  host:  'localhost',
  port:   80,
  name: 'sugimoto'
};

// アプリケーション内で使用
function App() {}
App.prototype.say = function() {
  alert('My name is: ' + Config.name);
};

var app = new App;
app.say(); // My name is: sugimoto

あまりいいサンプルではありませんが…。上記のコードに関して、アプリケーション起動中とかに、マニアックな人はデバッグツールとかでConfigの中身を書き換えたりするかもしれません。Config.name = 'オレオレ!'とかされると、当然ダイアログの表示情報も変わってしまいます。

このくらいなら問題ないですが、設定オブジェクトにアプリケーションのステータスとかが入っている場合、それを書き換えることで不正なステップを作ったりできるかもしれません。とにかく、グローバルなオブジェクトは外部から書き換えられるという懸念点で毎日震えてます。

Config取り込み&破棄パターン

そんなこんなで、私が採用しているパターンはこちら。

// 設定オブジェクト(varをつけないのがキモ)
Config = {
  host:   'localhost',
  port:   80,
  name: 'sugimoto'
};

(function() {

var conf = {};

// ----------------------------------------------------------

Object.keys(Config).forEach(function(key) {
  conf[key] = Config[key];
});
// varをつけてないのでdelete演算子で削除できるけど、念の為undefinedに
try {
  delete Config;
} catch ( e ) {
  Config = void 0;
}


// ----------------------------------------------------------

// アプリケーション内で使用
function App() {}
App.prototype.say = function() {
  alert('My name is: ' + conf.name);
};

window.App = App;
})();

var app = new App;
app.say(); // "常に" My name is: sugimoto

アプリケーションを匿名関数のクロージャで囲うのはよくやりますが、その中で設定オブジェクトの複製を作って取り込み、delete演算子でグローバルな方のConfigを削除してしまいます。

こうすることで、クロージャ内では初期設定がそのまま有効となり、かつ外部からの変更ができなくなり、設定の安全性が保たれます。より具体的に言うなら、Configの定義とAppを定義するクロージャの間にScript Insertionが起こらない限り、設定は正常にアプリケーションに渡されるでしょう。

取り込み後に動的に変更したい場合は、アプリケーションオブジェクトで設定変更できるメソッドとかを作ればOKですね。

この時、グローバルな設定であるConfigオブジェクトはvar宣言せずにあえてグローバル宣言するのがポイントです。varするとdeleteで削除できなくなるので。

多分ですけど

設定の項目はprimitiveなものが多いですが、シャローコピー元をdeleteで削除しても大丈夫なようです。

グローバルに作ってすぐ破棄するという覚え方でどうでしょうかね。

現場からは以上です。