不用意に(いわゆる)クロージャーを量産してはならない。
- 一度覚えだすと、使いたくなるクロージャーだが今後の為に覚書
var createCountDown = function ( n ) { var count = n; var func = function ( ) { return count--; }; return func; }; var count0 = createCountDown ( 10 ); var count1 = createCountDown ( 20 ); count0(); //--> 10 count0(); //--> 9 count1(); //--> 20 count0(); //--> 8
この関数 createCountDown の中の関数 func からは、変数 count と、n が参照できる。
しかも、関数 createCountDown を呼び出すたびに、新しい count と n が作り出される。
慣れてくると非常に便利。
- 正規表現で置き換えするときに、関数で処理する
(要素のstyleを、"background-color" から "backgroundColor" に変換する)
var hoge = function ( str /*String*/ ) { var fuga = function( a, b ) { return b.toUpperCase(); }; var result = str.replace( /-[a-z]/g, fuga ); return result; //一行なら return str.replace(/-[a-z]/g,function(a,b){return b.toUpperCase()}) };
この関数 fuga からも、外側の関数の変数 str は、参照できる。なのでこれもいわゆるクロージャー。
ところで、参照させないためにはどうするか?
- それは簡単なこと。関数 fuga を、外側で定義すればよい。
var fuga = function( a, b ) { return b.toUpperCase(); }; var hoge = function ( str /*String*/ ) { var result = str.replace( /-[a-z]/g, fuga ); return result; //一行なら return str.replace(/-[a-z]/g,function(a,b){return b.toUpperCase()}) };
しかし、関数 fuga は、関数 hoge のためだけにあるような関数。他の関数から使われないように
するにはどうするか?
もしくは、関数 fuga を定義してしまったために、fuga という名前を使えなくなってしまった。
それをどうするか?
- こんな形に変形できる
var hoge = (function ( fuga ) { return function ( str ) { return str.replace( /-[a-z]/g, fuga ); }; })(function( a, b ) { return b.toUpperCase(); });
- なんと version=1.8 では、関数の { } と return を省略できる。
<script type="application/javascript;version=1.8"> var hoge = (function ( fuga ) function ( str ) str.replace( /-[a-z]/g, fuga )) (function( a, b ) b.toUpperCase()); </script>
う〜〜ん。自分でも一発でこれを書けません。
- これを発展させて、配列の文字列を、変換するのに逆にも対応させると
<script type="application/javascript;version=1.8"> function hoge ( ary, flag ) ary.map( flag ? function ( a ) a.replace( /-([a-z])/g, function ( a, b ) b.toUpperCase() )://←この位置から見ると function ( a ) a.replace(/[A-Z]/g, function ( a ) '-' + a.toLowerCase() ) ); alert( [hoge( [ 'aB', 'bC' ], false ), hoge( [ 'a-b', 'b-c' ], true ) ] ); </script>
この場合だと、関数 function ( a, b ) のところからは、その外側、さらにその外側と参照できる環境が出来てしまっている。これでは大量にメモリーを消費する。(反省)
<script type="application/javascript;version=1.8"> var hoge = (function ( toUpper, toLower ) function( ary, flag ) ary.map( flag ? toUpper: toLower ))( (function ( up ) function( a ) a.replace( /-([a-z])/g, up ))( function ( a, b ) b.toUpperCase()), (function ( low ) function ( a ) a.replace(/[A-Z]/g, low ))( function ( a ) '-' + a.toLowerCase())); alert( [hoge( [ 'aB', 'bC' ], false ), hoge( [ 'a-b', 'b-c' ], true ) ] ); </script>
とにかく、「アホな書き方をすると大量にメモリーを消費してしまう」ということで。