2011年6月15日水曜日

[JavaScript]クロージャを使った、プライベート変数・関数の共有

C言語のようなクラスベースのオブジェクト指向言語では、staticを用いてプライベート変数・関数の共有をする。

では、JavaScriptのようなプロトタイプペースではどうするかという話。

呼び出すたびにカウントが1づつ増加していくcounter()という関数の例で考える。

何も考えずに作ると次のようになる。

var i = 0;
function counter(){
  i+=1;
}

counter(); //1
counter(); //2


問題は、変数iが関数の外に出ているがために、外部から簡単にアクセスできてしまうということ。
(グローバル変数は極力使いたくない)

オブジェクト指向でいうところの、変数の隠蔽をしつつ、この関数内だけで変数iを共有するためにはどうすればよいか?

ここでクロージャの出番となる。

var counter = (function(){
  var i=0;
  return function(){
    i+=1;
  };
})();

counter(); //1
counter(); //2


(function(){})()の部分で、無名関数を即実行する。

その結果counterに代入されるのは、return 以降に書かれている関数、
function(){i+=1};

である。では、このreturn文の前に書かれている var i=0;はどうなるか。

このiは最初に実行された後、消えず、全てのcounter()に共有され、参照されるようになる。

よって、counter()が呼ばれるたびにiは0に初期化されず、変更が反映される。


クロージャを使ってプライベート変数を共有する方法は、オブジェクトを作るときにも利用でき、

var counter = (function(){
  var i=0;
  reuturn {
    inc : function(){
      i += 1;
    },
    dec : function(){
      i -= 1;
    }
  };
})();


オブジェクト間で、共有する場合は基本的にこのパターン。