前回の「第4回:JavaScriptライブラリの作成」で作成したCalcライブラリでは、オブジェクトの初期化で特に複雑な処理は不要でしたが、より高度なライブラリになると多数の関数を定義したりループを回したりと、初期化処理の中で変数を必要になるシーンが増えてきます。
JavaScriptの変数スコープは「{}」で囲われたブロック単位でなく、関数単位になります。関数外でvar宣言した変数も全てグローバル変数として定義されるため、例えばライブラリ中で
リスト5:calc.cgiサンプルCGI(Webサービス側)
{
var tmp = 0;
for( var i=0; i<10; i++ ) {
// などなど、初期化処理を行う
}
}
という初期化コードを記述した場合、tmpとiの2つのグローバル変数を利用(汚染)することになります。
ライブラリは他のプログラムと併せて利用するためのものですから、ライブラリ外のプログラムが変数tmpやiを別の用途で利用していた場合に影響が出てしまう可能性があります。
ライブラリの初期化処理中で変数を利用する際にも、無用にグローバル変数を利用して他のプログラムに影響を与えないように、ライブラリ側で配慮しておく必要があります。
そこでJavaScriptでグローバル変数を汚染せずに初期化処理を行う場合には、無名関数を定義してその場で実行する手法が多く利用されています。
(function(){
var tmp = 0;
for( var i=0; i<10; i++ ) {
// などなど、初期化処理を行う
}
})();
このコードは、初めは少しわかりにくいかもしれませんが、まず「(function(){ 〜 })」の部分が無名関数の定義になります。その直後に再びカッコ()が置かれているため、定義した無名関数がその場で実行されるというトリックです。
この場合、関数の中でvar宣言しているので、関数内で変数tmpやiをいくら書き換えても、グローバル変数には影響がありません。名前のない関数を作成してその場で実行することで、変数スコープの問題を回避しています。
また、別の手法としては、無名オブジェクトを利用する手法もあります。
new function(){
var tmp = 0;
for( var i=0; i<10; i++ ) {
// などなど、初期化処理を行う
}
};
こちらも変数スコープが関数内となり、同様の効果が得られます。まず「function(){ 〜 }」で無名関数としてオブジェクトのコンストラクタメソッドを定義し、その直前のnewによりインスタンス生成することで、その場で無名関数内のコードが実行されるトリックです。
カッコ()の個数が削減できて見た目にも分かりやすく、単純にコードブロック{}の冒頭にオマジナイとして「new function()」を付けるだけでグローバル変数の汚染を防げるので、お手軽ですね。
|