2 X_CLOSURE_LIVE_LIST = [],
\r
4 X_CLOSURE_POOL_LIST = [],
\r
6 X_Closure_COMMAND_BACK = X_CLOSURE_LIVE_LIST,
\r
8 X_Closure_COMMAND_DROP = X_CLOSURE_POOL_LIST,
\r
10 X_CLOSURE_THIS_FUNC = 1,
\r
11 X_CLOSURE_HANDLEEVENT = 2,
\r
12 X_CLOSURE_FUNC_ONLY = 3,
\r
13 X_CLOSURE_THIS_FUNCNAME = 4;
\r
16 * <p>クロージャに関するポリシーと再利用可能クロージャについて次の記事をご覧ください。
\r
17 * <a href="http://outcloud.blogspot.jp/2015/05/reusable-closure.html" target="_blank">再利用できるクロージャを使ったWebアプリケーション開発</a>
\r
19 * <h5>再利用可能クロージャの作成</h5>
\r
20 * X_Closure_create() で再利用可能なクロージャの作成。次のパターンで呼び出します。<br>
\r
21 * 最大で三つの引数を並べる一連のパターンは、 EventDispatcher.listen unlisten, listening や X.Timer.add, once でも使われますので、ここでよく目を通しておきます。
\r
23 * <h5>再利用可能クロージャの破棄と再利用</h5>
\r
24 * X_Closure_correct() によってクロージャは回収され再利用に備えます。<br>
\r
25 * 実は、クロージャが束縛するのは、this コンテキストやコールバック関数といった、<strong>そのもの</strong>ではなく、それらを一定のルールで格納したハッシュです。<br>
\r
26 * このハッシュはクロージャに与えた後も、適宜に取得が可能です。このハッシュのメンバーを書き換えることで、クロージャの this コンテキストやコールバック関数を書き換えています。
\r
28 * @class __CallbackHash__
\r
29 * @classdesc コールバック関数に this コンテキストや、追加の引数を設定するための情報を収めたハッシュです。<br>
\r
30 * フレームワークユーザは直接触ることにはないが、重要な情報なので書いておきます。
\r
33 var __CallbackHash__ =
\r
34 /** @lends __CallbackHash__.prototype */
\r
37 * コールバックの種類を表す数値。 this + function, this.handleEvent, function only がある。
\r
40 cbKind : X_CLOSURE_THIS_FUNC,
\r
43 * @type {funciton|undefined}
\r
47 * コールバック名。コールバック作成時に関数が無い、関数が入れ替わっていても動作する。
\r
48 * @type {string|undefined}
\r
50 funcName : undefined,
\r
52 * コールバックの this コンテキスト。
\r
53 * @type {object|undefined}
\r
55 context : undefined,
\r
57 * コールバックに追加する引数。イベントのコールバックでは event オブジェクトのあとに追加されるため supplement[0] が第一引数にならない点に注意。
\r
58 * @type {Array|undefined}
\r
60 supplement : undefined,
\r
62 * __CallbackHash__ の情報を元に、コールバックを実施するプロキシ。
\r
65 proxy : X_Closure_proxyCallback
\r
68 // ------------------------------------------------------------------------- //
\r
69 // --- implements ---------------------------------------------------------- //
\r
70 // ------------------------------------------------------------------------- //
\r
72 function X_Closure_create( thisObject, opt_callback, opt_args /* [ listener || ( context + function ) || function ][ args... ] */ ){
\r
73 var obj = X_Closure_classifyCallbackArgs( thisObject, opt_callback, opt_args ),
\r
76 if( !obj.cbKind ) return obj;
\r
78 if( l = X_CLOSURE_POOL_LIST.length ){
\r
79 ret = X_CLOSURE_POOL_LIST[ l - 1 ]; --X_CLOSURE_POOL_LIST.length; // ret = X_CLOSURE_POOL_LIST.pop();
\r
80 _obj = ret( X_Closure_COMMAND_BACK );
\r
82 _obj.cbKind = obj.cbKind;
\r
83 _obj.funcName = obj.funcName;
\r
84 _obj.func = obj.func;
\r
85 _obj.context = obj.context;
\r
86 _obj.supplement = obj.supplement;
\r
87 _obj.proxy = X_Closure_proxyCallback;
\r
89 ret = X_Closure_actualClosure( obj );
\r
90 obj.proxy = X_Closure_proxyCallback;
\r
92 X_CLOSURE_LIVE_LIST[ X_CLOSURE_LIVE_LIST.length ] = ret;
\r
97 function X_Closure_classifyCallbackArgs( arg1, arg2, arg3, alt_context ){
\r
100 if( X_Type_isObject( arg1 ) && X_Type_isFunction( arg2 ) ){
\r
101 obj = { context : arg1, func : arg2, cbKind : X_CLOSURE_THIS_FUNC };
\r
103 if( X_Type_isObject( arg1 ) ){
\r
104 if( arg2 && X_Type_isString( arg2 ) ){
\r
105 obj = { context : arg1, funcName : arg2, cbKind : X_CLOSURE_THIS_FUNCNAME };
\r
107 obj = { context : arg1, cbKind : X_CLOSURE_HANDLEEVENT };
\r
111 if( X_Type_isFunction( arg1 ) ){
\r
114 obj = { context : alt_context, func : arg1, cbKind : X_CLOSURE_THIS_FUNC };
\r
116 obj = { func : arg1, cbKind : X_CLOSURE_FUNC_ONLY };
\r
119 if( X_Type_isFunction( arg2 ) ){
\r
120 //console.log( 'X_Closure_classifyCallbackArgs : arg1 が ' + arg1 + 'です' ); ie4 で error
\r
122 obj = { context : alt_context, func : arg2, cbKind : X_CLOSURE_THIS_FUNC };
\r
124 obj = { func : arg2, cbKind : X_CLOSURE_FUNC_ONLY };
\r
127 if( alt_context && X_Type_isString( arg1 ) ){
\r
129 obj = { context : alt_context, funcName : arg1, cbKind : X_CLOSURE_THIS_FUNCNAME };
\r
132 obj = { context : alt_context, cbKind : X_CLOSURE_HANDLEEVENT };
\r
135 console.log( '不正 ' + arg1 );
\r
136 console.dir( arg1 );
\r
140 if( X_Type_isArray( arg3 )){
\r
141 obj.supplement = arg3;
\r
143 return ( obj.context || obj.supplement ) ? obj : arg1;
\r
146 function X_Closure_actualClosure( obj ){
\r
148 if( arguments[ 0 ] === X_Closure_COMMAND_BACK ) return obj;
\r
149 if( arguments[ 0 ] !== X_Closure_COMMAND_DROP ) return obj.proxy && obj.proxy( obj, arguments );
\r
153 function X_Closure_proxyCallback( xfunc, _args ){
\r
154 var args = _args || [],
\r
155 thisObj = xfunc.context,
\r
157 supp = xfunc.supplement,
\r
158 temp, ret, funcName;
\r
160 if( supp && supp.length ){
\r
164 args.length === 1 ?
\r
165 ( temp[ 0 ] = args[ 0 ] ) :
\r
166 temp.push.apply( temp, args )
\r
168 supp.length === 1 ?
\r
169 ( temp[ temp.length ] = supp[ 0 ] ) :
\r
170 temp.push.apply( temp, supp );
\r
174 switch( xfunc.cbKind ){
\r
176 case X_CLOSURE_THIS_FUNC :
\r
177 return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );
\r
179 case X_CLOSURE_THIS_FUNCNAME :
\r
180 funcName = xfunc.funcName;
\r
181 case X_CLOSURE_HANDLEEVENT :
\r
182 funcName = funcName || 'handleEvent';
\r
183 temp = thisObj[ funcName ];
\r
184 if( X_Type_isFunction( temp ) ){
\r
185 return args.length === 0 ? thisObj[ funcName ]() :
\r
186 args.length === 1 ? thisObj[ funcName ]( args[ 0 ] ) : temp.apply( thisObj, args );
\r
190 if( temp !== func && X_Type_isFunction( temp ) ){
\r
191 return args.length === 0 ? thisObj[ 'handleEvent' ]() : temp.apply( thisObj, args );
\r
193 if( X_Type_isFunction( thisObj ) ){
\r
194 return args.length === 0 ? thisObj.call( thisObj ) : thisObj.apply( thisObj, args );
\r
196 return args.length === 0 ? func.call( thisObj ) : func.apply( thisObj, args );*/
\r
198 case X_CLOSURE_FUNC_ONLY :
\r
199 return args.length === 0 ?
\r
201 args.length === 1 ?
\r
202 func( args[ 0 ] ) :
\r
203 func.apply( null, args );
\r
205 return X_CALLBACK_NONE;
\r
208 function X_Closure_correct( f ){
\r
209 var i = X_CLOSURE_LIVE_LIST.indexOf( f ),
\r
213 X_CLOSURE_LIVE_LIST.splice( i, 1 );
\r
214 X_CLOSURE_POOL_LIST[ X_CLOSURE_POOL_LIST.length ] = f;
\r
215 obj = f( X_Closure_COMMAND_BACK );
\r
216 X_Object_clear( obj );
\r
221 function X_Closure_monitor(){
\r
223 'Callback:Live' : X_CLOSURE_LIVE_LIST.length,
\r
224 'Callback:Pool' : X_CLOSURE_POOL_LIST.length
\r
227 function X_Closure_gc(){
\r
228 X_CLOSURE_POOL_LIST.length = 0; // ?
\r
231 X_TEMP.onSystemReady.push( function( sys ){
\r
232 sys.monitor( X_Closure_monitor );
\r
233 sys.gc( X_Closure_gc );
\r