JavaScriptでクロージャ

f1 = function(){return 1;};
f2 = function(){ return 3+f1();};
f1 = function(){return 10;};
f2();

13

クロージャとして使うにはf2を定義したときその環境(=ここではf1の定義)を引きずって欲しいわけだからこれは意図した結果ではない。

f1 = function(){return 1;};
f2 = function(){ return (function(f){return 3+f();})(f1);};
f1 = function(){return 10;};
f2();

13

これもだめ

f1 = function(){return 1;};
f2 = (function(f){return (function(){return 3+f();}) })(f1);
f1 = function(){return 10;};
f  = function(){return 20;};
f2();

4

これでようやく意図した結果になった

関数は評価される時点のものが使われるようだ
↑これがないと関数の動的な書き換えができないわけで。

三番目ではf2の定義時のf1はfのスコープ(=引数のスコープ)に限定されるので外部から変更は不可能になる。
要するに関数を返す関数が必要になるってこと

スコープの問題なので

f1 = function(){return 1;};
(function(){
  var f = f1;
  f1 = function(){return 3+f();};
})();
f=function(){return 20;};
f1();

これでもいい。finalとthisがついたらjavaでよく見る形だ

f1={foo :1,  fun : function(){return this.foo} };
f2 = (function(f){return (function(){return 3+f.fun();}) })(f1);
f1.foo = 10;
f2();

13

さっきの成功例と形は同じだが…
オブジェクトは参照渡しなので当然こうなる。
(ただしプリミティブなデータは値渡し)

f1={foo :1,  fun : function(){return this.foo} };
f2 = (function(f){return (function(){return 3+f.fun();}) })(eval(uneval(f1)));
f1.foo = 10;
f2();

4

ディープコピーをしてやる。
unevalはfirefox固有かも。