仕事が忙しい;;師走だから?
最近、仕事の関係でjavascrpt触ることが多くなって、ふと調べたらjavascriptのクロージャでメモリリークが簡単に発生することを知りました。
でも、古めな記事ばかりなので、最近のモダンブラウザでは対応済みかもしれません。
いくつか記事を見てたら、クロージャとメモリリークについてのコピペ – JavaScriptとかPerlとかPHPとかさくらVPSとか勉強するに、createLeakFreeClosure なるものが載ってましたが、こんなややこしいことしないと駄目なのかなぁ、と自分なりに考えてみました。
で、思い着いたのがこれ。
1 function unClosure(fn) {
2 return new Function('return function(){'
3 + ' return (' + fn.toString() + ').apply(this, arguments);'
4 + '}'
5 );
6 }
Function.toString()から、new Function で関数を作り直してます。
一部の参照を残したいときもあるかなと思ってのver.2
with使ってるから微妙?
1 function unClosure(fn, use) {
2 return (new Function('__with__',
3 'with(__with__){'
4 + ' return function(){'
5 + ' return (' + fn.toString() + ').apply(this, arguments);'
6 + ' }'
7 + '}'
8 )(use));
9 }
with使わないとこんな感じかな
1 function unClosure(fn, use) {
2 var k, vals = [], vars = [];
3 for (k in use){
4 if (use.hasOwnProperty(k)) {
5 vars.push(k + '=c[' + vals.length + ']');
6 nulls.push(k + '=null');
7 vals.push(use[k]);
8 }
9 }
10 return (new Function('c',
11 'return (function(){'
12 + ((0 < vars.length) ? ' var ' + vars.join(',') + ';' : '')
13 + ' var r;'
14 + ' r = (' + fn.toString() + ').apply(this,arguments);'
15 + ' ' + nulls.join(',') + ';'
16 + ' return r;'
17 + '}.apply(this,arguments));'
18 )(vals));
19 }
Function.prototype.unclosure = function(){ return unClosure(this, arguments[0]); };ってしとけば
1 var img = document.getElementsByTagName('img')[0];
2 img.onclick = (function(){ alert(v); }).unclosure({v:'unclosure'});
こんな感じで使える。
変数の参照は切れたので、たぶんcreateLeakFreeClosureの代わりになるかな?
elementを変数に入れてて、それをクロージャ内で参照 って場合にちゃんとメモリリークしないかは、検証が必要そう…