OSDN Git Service

Fix the bug of X.NodeAnime.
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 13_XClass.js
1 \r
2 // ------------------------------------------------------------------------- //\r
3 // ------------ local variables -------------------------------------------- //\r
4 // ------------------------------------------------------------------------- //\r
5 var\r
6         /**\r
7          * 全てのクラスのスーパークラスのようなもの。(ライブラリ内にカプセル化されているため、ユーザが触ることはありません)<br>\r
8          * X.Class.create() で定義されたクラスのインスタンスが共通で備えるメソッド を確認してください。\r
9          * @class __ClassBase__\r
10          * @private\r
11          * @abstract\r
12          */\r
13         __ClassBase__ = {\r
14                         /**\r
15                          * クラス名\r
16                          * @type {string}\r
17                          */\r
18                         NAME         : ''\r
19                 },\r
20 \r
21         X_Class_CLASS_LIST         = [],\r
22         X_Class_DEF_LIST           = [],\r
23         X_Class_SUPER_CALLER       = [],\r
24         X_Class_SUPER_STACKS       = [],\r
25         X_Class_traits             = null,\r
26         X_Class_useObjectCreate    = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf\r
27         // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を辞めると動作,,,\r
28         X_Class_use_proto_         = !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] &&\r
29                                                                 // Android で原因不明のエラーに遭遇しているのは、この辺りが怪しい... 2016.3.9\r
30                                                                  !X_UA[ 'AOSP' ] && !X_UA[ 'ChromeWV' ] &&\r
31                                                                         !!X_emptyFunction.prototype.__proto__,\r
32         X_Class_constructorFix     = X_UA[ 'AOSP' ] < 3 || X_UA[ 'iOS' ] < 5,\r
33         X_Class_SEAL_KILLING       = [],\r
34 \r
35 X_Class_CommonMethods =\r
36 /** @lends __ClassBase__.prototype */\r
37 {\r
38         /**\r
39          * 全ての動的メンバを削除して、インスタンスを破棄する。<br>\r
40          * インスタンスが X.EventDispatcher とそのサブクラスの場合、次の動作をする。\r
41          * <ol>\r
42          * <li>X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X.Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。この間に kill() が呼ばれても無視される。\r
43          * <li>破棄に進む場合は、X.Event.KILL_INSTANCE を発火する。\r
44          * <li>dispatch 中は、インスタンスの全ての dispatch が終了するまで実際の破棄を待つ。\r
45          * <li>実際の破棄では、インスタンスのメンバの削除に加えて全てのイベントリスナを解除する。\r
46          */\r
47         // TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ\r
48         'kill' : function(){\r
49                 var listeners, flag, p, i, list, timers, def;\r
50                 \r
51                 // TODO 破棄済のインスタンスへの kill\r
52                 \r
53                 if( this[ 'instanceOf' ]( X_EventDispatcher ) ){\r
54 \r
55                         listeners = this[ '_listeners' ];\r
56 \r
57                         // SEAL のタイミングは、イベント中なので listeners が存在する\r
58                         if( listeners && X_Class_SEAL_KILLING.length && X_Class_SEAL_KILLING.indexOf( this ) !== -1 ) return;\r
59 \r
60                         // listeners がない場合、イベントの登録がないため、BEFORE_KILL_INSTANCE は呼ばれない。\r
61                         // KILL_RESERVED == true の場合、BEFORE_KILL_INSTANCE は呼ばれない。\r
62                         if( listeners && !listeners[ X_LISTENERS_KILL_RESERVED ] && listeners[ X_EVENT_BEFORE_KILL_INSTANCE ] ){\r
63                                 X_Class_SEAL_KILLING[ i = X_Class_SEAL_KILLING.length ] = this;\r
64                                 \r
65                                 if( this[ 'dispatch' ]( X_EVENT_BEFORE_KILL_INSTANCE ) & X_CALLBACK_PREVENT_DEFAULT ){\r
66                                         this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE_CANCELED );\r
67                                         // BEFORE_KILL_INSTANCE, KILL_INSTANCE_CANCELED 内で kill() しても PREVENT_DEFAULT の場合はこれを無視する。\r
68                                         flag = true;\r
69                                 };\r
70                                 \r
71                                 X_Class_SEAL_KILLING.length === 1 ?\r
72                                         ( X_Class_SEAL_KILLING.length = 0 ) :\r
73                                         X_Class_SEAL_KILLING.splice( X_Class_SEAL_KILLING[ i ] === this ? i : X_Class_SEAL_KILLING.indexOf( this ), 1 );\r
74 \r
75                                 if( flag ) return;\r
76                         };\r
77 \r
78                         if( listeners = this[ '_listeners' ] ){// unlisten 等で listeners が破棄されている場合があるので取り直し。\r
79                                 if( listeners[ X_LISTENERS_DISPATCHING ] ){\r
80                                         listeners[ X_LISTENERS_KILL_RESERVED ] = true;\r
81                                         return;\r
82                                 };\r
83                                 \r
84                                 if( listeners[ X_EVENT_KILL_INSTANCE ] ){\r
85                                         X_Class_SEAL_KILLING[ i = X_Class_SEAL_KILLING.length ] = this;\r
86 \r
87                                         listeners[ X_LISTENERS_KILL_RESERVED ] = false;                                 \r
88                                         this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE );\r
89                                         \r
90                                         X_Class_SEAL_KILLING.length === 1 ?\r
91                                                 ( X_Class_SEAL_KILLING.length = 0 ) :\r
92                                                 X_Class_SEAL_KILLING.splice( X_Class_SEAL_KILLING[ i ] === this ? i : X_Class_SEAL_KILLING.indexOf( this ), 1 );\r
93                                 };\r
94 \r
95                                 if( !( listeners = this[ '_listeners' ] ) ){\r
96                                         for( p in listeners ){\r
97                                                 //if( X_EMPTY_OBJECT[ opt_type ] ) continue;\r
98                                                 if( p <= X_LISTENERS_KILL_RESERVED ) continue;\r
99                                                 list = listeners[ p ];\r
100                                                 for( i = list.length; i; ){\r
101                                                         this[ 'unlisten' ]( p, list[ --i ] );\r
102                                                 };\r
103                                         };                                      \r
104                                 };\r
105                         };\r
106 \r
107                         if( this[ 'instanceOf' ]( Node ) ){\r
108                                 // console.log( 'KILL : ' + this.call( 'outerHTML' ) );\r
109                                 X_Node_onKill( this );\r
110                         };\r
111 \r
112                         timers = X_EventDispatcher_LAZY_TIMERS;\r
113 \r
114                         // asyncDispatch の削除\r
115                         for( p in timers ){\r
116                                 if( timers[ p ] === this ){\r
117                                          // delete X_EventDispatcher_LAZY_TIMERS[ p ]; コレ不要\r
118                                         X_Timer_remove( p );\r
119                                 };\r
120                         };\r
121                 };\r
122                 \r
123                 X_Object_clear( this );\r
124                 \r
125                 def = X_Class_getClassDef( this );\r
126                 \r
127                 if( def.pool ){\r
128                         def.live.splice( def.live.indexOf( this ), 1 );\r
129                         def.pool[ def.pool.length ] = this;\r
130                 };\r
131         },\r
132         \r
133         /**\r
134          * 関数は Constructor 内で使用します。クラス定義を辿ってスーパークラスのコンストラクタを呼び出します。<br>\r
135          * 内部的には、呼び出したコンストラクタは配列に控え(X_Class_CALLING_SUPER)、呼び出したコンストラクタ内でさらに Super が呼ばれた場合、配列を元にさらにスーパーなコンストラクタを辿ります。\r
136          * @example Constructor : function( arg1, arg2 ){\r
137          *      this.Super( aeg1, arg2 );\r
138          * }\r
139          * @param var_args {...?} 親コンストラクタを呼ぶ際に渡す任意の数の引数\r
140          * @return {*}\r
141          */\r
142         // TODO 現在 new しているインスタンスを保持してチェックする\r
143         'Super' : function( var_args ){\r
144                 var me     = this,\r
145                         sClass = me.constructor,\r
146                         i      = X_Class_SUPER_CALLER.indexOf( me ),\r
147                         stack, t, def, ret;\r
148         \r
149                 if( i === -1 ){\r
150                         X_Class_SUPER_CALLER[ i = X_Class_SUPER_CALLER.length ] = me;\r
151                         t = stack = X_Class_SUPER_STACKS[ i ] = 0;\r
152                 } else {\r
153                         t = stack = X_Class_SUPER_STACKS[ i ];\r
154                         \r
155                 while( t ){\r
156                         sClass = X_Class_getClassDef( sClass ).SuperClass;\r
157                     --t;\r
158                 };                      \r
159                 };\r
160 \r
161                 while( sClass ){\r
162                         ++t;\r
163                         sClass = X_Class_getClassDef( sClass ).SuperClass;\r
164                         if( !sClass ) break;\r
165                         def    = X_Class_getClassDef( sClass );\r
166                         \r
167                         if( def.Constructor ){\r
168                                 X_Class_SUPER_STACKS[ i ] += t;\r
169                                 ret = def.Constructor.apply( me, arguments );\r
170                                 break;\r
171                         };\r
172                 };\r
173                 \r
174                 // index が替わっている可能性があるので取り直し\r
175                 if( X_Class_SUPER_CALLER[ i ] !== me ) i = X_Class_SUPER_CALLER.indexOf( me );\r
176                 \r
177                 if( X_Class_SUPER_STACKS[ i ] === stack ){\r
178                         //console.log( 'スーパークラス、またはスーパークラスのコンストラクタは存在しません' );\r
179                 };\r
180                 \r
181                 if( stack === 0 ){\r
182                         X_Class_SUPER_CALLER.splice( i, 1 );\r
183                         X_Class_SUPER_STACKS.splice( i, 1 );\r
184                 } else {\r
185                         X_Class_SUPER_STACKS[ i ] = stack;\r
186                 };\r
187                 return ret || me;\r
188         },\r
189 \r
190         /**\r
191          * myFunc について、スーパークラスで設定されている同名の関数を呼び出す。<br>\r
192          * 低速な関数なので多用されるべきではありません!<br>\r
193          * 第一引数に自身の(自身から参照できる)関数を指定します。内部では関数名を調べた上で prototype チェーンをゴリゴリ辿る、特別なことはしていません。<br>\r
194          * superCall と Super がネストする場合も現在のクラス階層を X_Class_SUPER_CALLER, X_Class_SUPER_STACKS を使って控えているので、意図した親関数が呼ばれます。<br>\r
195          * 次の理由によって、関数名で辿ることは非推奨です。\r
196          * <ol>\r
197          * <li>closur compiler でメソッド名が変更される\r
198          * </ol>\r
199          * 次の場合、意図した動作が得られません。\r
200          * <ol>\r
201          * <li>2つ以上の異なる名前で同じ関数がメンバーがいた場合\r
202          * <li>サブクラスの prototype にスーパークラスと同じ関数をコピーしている\r
203          * <li>非関数でメンバーを上書きしている\r
204          * <li>superCall 以外の手段で親関数を呼び、そのなかで superCall を呼んだ\r
205          * </ol>\r
206          * 通常の X.Class.create の書き方ではこのような状況は起きませんが、js はなんでもいろいろ出来てしまいますから…<br>\r
207          * 参考:<a href="http://qiita.com/no22@github/items/d3bead2acbb7ff1fb86b" target="_blank">ES5なJavascriptでモダンなクラス的継承&スーパー呼び出し </a><br>\r
208          * original:<a href="http://javascript.crockford.com/inheritance.html" target="_blank">Classical Inheritance in JavaScript</a>\r
209          * @param myFunc {Function|string} オーバーライド済の自身の(自身から参照できる)関数。\r
210          * @param var_args {...*} オーバーライド元関数に渡す任意の数の引数\r
211          * @example return this.superCall( this.myFunc, param0, param1, ... );\r
212          * @return {*} オーバーライド元の関数を呼び出した戻り値。\r
213          */\r
214         'superCall' : function( myFunc, var_args ){\r
215                 var me     = this,\r
216                         sClass = me.constructor,\r
217                         proto  = sClass.prototype,\r
218                         i      = X_Class_SUPER_CALLER.indexOf( me ),\r
219                         args   = arguments,\r
220                         p, name, stack, t, sFunc, ret;\r
221 \r
222                 if( X_Type_isFunction( myFunc ) ){\r
223                         for( p in proto ){\r
224                                 if( proto[ p ] === myFunc ){\r
225                                         name = p;\r
226                                         break;\r
227                                 };\r
228                         };\r
229                         if( !name ) return;\r
230                 } else\r
231                 if( X_Type_isString( myFunc ) && X_Type_isFunction( me[ myFunc ] ) ){\r
232                         name = myFunc;\r
233                 } else {\r
234                         return;\r
235                 };\r
236                         \r
237                 if( i === -1 ){\r
238                         X_Class_SUPER_CALLER[ i = X_Class_SUPER_CALLER.length ] = me;\r
239                         t = stack = X_Class_SUPER_STACKS[ i ] = 0;\r
240                 } else {\r
241                         t = stack = X_Class_SUPER_STACKS[ i ];\r
242                         \r
243                 while( t ){\r
244                         sClass = X_Class_getClassDef( sClass ).SuperClass;\r
245                     --t;\r
246                 };                      \r
247                 };\r
248 \r
249         if( sClass ){\r
250                 myFunc = sClass.prototype[ name ];\r
251 \r
252                         while( sClass ){\r
253                                 ++t;\r
254                                 sClass = X_Class_getClassDef( sClass ).SuperClass;      \r
255                                 sFunc  = sClass.prototype[ name ];\r
256                                 \r
257                                 if( sFunc !== myFunc /* X_Object_own( name, sClass.prototype ) */ ){\r
258                                         if( X_Type_isFunction( sFunc ) ){\r
259                                                 X_Class_SUPER_STACKS[ i ] += t;\r
260                                                 switch( args.length ){\r
261                                                         case 1 :\r
262                                                                 ret = sFunc.call( me );\r
263                                                                 break;\r
264                                                         case 2 :\r
265                                                                 ret = sFunc.call( me, args[ 1 ] );\r
266                                                                 break;\r
267                                                         case 3 :\r
268                                                                 ret = sFunc.call( me, args[ 1 ], args[ 2 ] );\r
269                                                                 break;\r
270                                                         case 4 :\r
271                                                                 ret = sFunc.call( me, args[ 1 ], args[ 2 ], args[ 3 ] );\r
272                                                                 break;\r
273                                                         default :\r
274                                                                 args = X_Array_copy( args );\r
275                                                                 args.shift();\r
276                                                                 ret = sFunc.apply( me, args );\r
277                                                                 break;                                                  \r
278                                                 };\r
279                                         };\r
280                                         break;\r
281                                 };\r
282                         };\r
283                 };\r
284 \r
285                 // index が替わっている可能性があるので取り直し\r
286                 if( X_Class_SUPER_CALLER[ i ] !== me ) i = X_Class_SUPER_CALLER.indexOf( me );\r
287 \r
288                 if( stack === 0 ){\r
289                         X_Class_SUPER_CALLER.splice( i, 1 );\r
290                         X_Class_SUPER_STACKS.splice( i, 1 );\r
291                 } else {\r
292                         X_Class_SUPER_STACKS[ i ] = stack;\r
293                 };\r
294                 return ret;\r
295         },\r
296         \r
297         /**\r
298          * インスタンスのクラスか?またはスーパークラスか?調べる。<br>\r
299          * instanceof 構文をサポートしない環境(IE5以下)を想定する場合、必ずこのメソッドを使用すること。<br>\r
300          * クラスのインスタンスか?だけ調べたい場合は this.constructor === klass が高速。\r
301          * @param klass {__ClassBase__} クラス定義\r
302          * @return {boolean}\r
303          */\r
304         // TODO instanceof に対応したブラウザはそちらを使用\r
305         'instanceOf' : function( klass ){\r
306                 var Super = this;\r
307 \r
308                 if( this.constructor === klass ) return true;\r
309                 while( Super = X_Class_getClassDef( Super ).SuperClass ){\r
310                         if( Super === klass ) return true;\r
311                 };\r
312                 return false;\r
313         }\r
314 };\r
315 \r
316 // ------------------------------------------------------------------------- //\r
317 // --- interface ----------------------------------------------------------- //\r
318 // ------------------------------------------------------------------------- //\r
319 \r
320 /*\r
321  * @enum {number}\r
322  * @const\r
323  */\r
324 var X_Class = {\r
325         NONE         :  0,\r
326         POOL_OBJECT  :  1,\r
327         ABSTRACT     :  2,\r
328         FINAL        :  4,\r
329         SINGLETON    :  8\r
330 };\r
331 \r
332 /**\r
333  * <p>Class を定義し システムの管理下に置く。\r
334  * <p>prototype 継承のブラウザ毎の差異も吸収し、 以下から最適な方法をしてくれる。\r
335  * \r
336  * <ol>\r
337  * <li>Object.create はパフォーマンスが悪そうなので現在は使っていない。\r
338  * <li>SubClass.prototype.__proto__ = SuperClass.prototype;\r
339  * <li>SubClass.prototype = new SuperClass;\r
340  * </ol>\r
341  * \r
342  * <ol>\r
343  * <li>X.Class.create( opt_settings, opt_name, opt_props ) でクラスを登録.\r
344  * <li>コンストラクタ となるメソッドは、opt_props 内の Constructor : function( arg ){ ... }, に書く.\r
345  * <li>通常通り new で インスタンス生成\r
346  * <li>kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.\r
347  * <li>pool が有効の場合、new で pool されたインスタンスが返される.\r
348  * </ol>\r
349  * @namespace X.Class\r
350  * @alias X.Class\r
351  */ \r
352 X[ 'Class' ] = /** @lends X.Class */ {\r
353 \r
354     /**\r
355      * 設定なし。\r
356      * @const\r
357      */ \r
358         'NONE'         : X_Class.NONE,\r
359         \r
360         // TODO この指定、フレームワーク内だけ!\r
361     /**\r
362      * インスタンスは破棄時(this.kill())に回収され、次回の new MyClass() 時に再利用されます。\r
363      * @const\r
364      */\r
365         'POOL_OBJECT'  :  X_Class.POOL_OBJECT,\r
366         \r
367         /**\r
368          * 定義するクラスは抽象クラスになります。new AbstractClass() とするとエラーになります。\r
369          * @const\r
370          */\r
371         'ABSTRACT'     :  X_Class.ABSTRACT,\r
372 \r
373         /**\r
374          * クラスの継承を禁止する。\r
375          * @const\r
376          */\r
377         'FINAL'        :  X_Class.FINAL,\r
378 \r
379         /**\r
380          * 未実装。でも目印になるので付けておきましょう。\r
381          * @const\r
382          */\r
383         'SINGLETON'    : X_Class.SINGLETON,\r
384 \r
385         'create'       : X_Class_create\r
386         \r
387         // TODO collect\r
388 };\r
389 \r
390 \r
391 \r
392 // ------------------------------------------------------------------------- //\r
393 // --- implements ---------------------------------------------------------- //\r
394 // ------------------------------------------------------------------------- //\r
395         /**\r
396          * クラスを定義する。<br>\r
397          * X.Class.create() によるクラス定義は必ずしもコンストラクタ('Constructor')を必要としません。クラス定義時にコンストラクタが未設定の場合、スーパークラスがあればそのコンストラクタを使用します。\r
398          * @alias X.Class.create\r
399          * @param {string} [displayName] クラスの名前\r
400          * @param {number} [classSetting=0] X_Class.POOL_OBJECT | X_Class.FINAL など\r
401          * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと\r
402          * @return {__ClassBase__}\r
403          * @example var myClass = X.Class.create(\r
404          *      'myClass',\r
405          *  X.Class.FINAL,\r
406          *  {\r
407          *       name : '',\r
408          *       Constructor : function( obj ){\r
409          *        this.name = obj.name;\r
410          *       },\r
411          *       getName : function(){\r
412          *        return this.name;\r
413          *       },\r
414          *       setName : function(v){\r
415          *        this.name = v;\r
416          *       }\r
417          *  }\r
418          * );\r
419          */\r
420         function X_Class_create( /* displayName, classSetting, privateClass, props */ ){\r
421                 var args        = X_Array_copy( arguments ),\r
422                         displayName = args[ 0 ],\r
423                         classSetting,\r
424                         opt_pool, opt_abstract, opt_final,\r
425                         privateDef,\r
426                         props,\r
427                         klass,\r
428                         classDef = {},\r
429                         cbHash = { proxy : X_Class_actualConstructor, classDef : classDef };\r
430 \r
431                 if( X_Type_isString( displayName ) === true ){\r
432                         classDef.displayName = displayName;\r
433                         args.shift();\r
434                 };\r
435                 \r
436                 // クラス設定\r
437                 classDef.setting = classSetting = args[ 0 ];\r
438                 if( X_Type_isNumber( classSetting ) ){\r
439                         opt_pool     = !!( classSetting & X_Class.POOL_OBJECT  );\r
440                         opt_abstract = !!( classSetting & X_Class.ABSTRACT     );\r
441                         opt_final    = !!( classSetting & X_Class.FINAL        );\r
442                         if( opt_final && opt_abstract ){\r
443                                 X.Logger.critical( 'final & Abstract!' );\r
444                                 return;\r
445                         };      \r
446                         args.shift();\r
447                 } else {\r
448                         classDef.setting = 0;\r
449                 };\r
450                 \r
451                 // インスタンスのメンバー\r
452                 props = args[ 0 ];\r
453                 if( !X_Type_isObject( props ) ){\r
454                         // クラスメンバ用オブジェクトが無しでもクラスは作成可能\r
455                         props = {};\r
456                 } else\r
457                 if( props[ 'Constructor' ] ){\r
458                         //{+dev\r
459                         if( !X_Type_isFunction( props[ 'Constructor' ] ) ){\r
460                                 alert( '"Constructor" is not function.' );\r
461                                 return;\r
462                         };\r
463                         //}+dev\r
464                         classDef.Constructor = props[ 'Constructor' ];\r
465                 };\r
466 \r
467                 klass  = X_Closure_actualClosure( cbHash ); // TODO callbackHash を class定義の置き場所にしてしまう!なるほど…\r
468                 cbHash.klass = klass;\r
469                 klass[ 'superClassOf' ] = X_Class_superClassOf;\r
470                 klass[ 'subClassOf' ]   = X_Class_subClassOf;\r
471                 \r
472                 if( X_Class_useObjectCreate ){\r
473                         klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonMethods, false );\r
474                         klass.prototype.constructor = klass;\r
475                 } else\r
476                 if( X_Class_use_proto_ ){\r
477                         X_Class_override( klass.prototype, props, true );\r
478                         if( X_Class_traits ){\r
479                                 klass.prototype.__proto__ = X_Class_traits;\r
480                         } else {\r
481                                 X_Class_override( klass.prototype, X_Class_CommonMethods, false );\r
482                         };\r
483                 } else {\r
484                         klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonMethods, false );\r
485                         klass.prototype.constructor = klass;\r
486                 };\r
487                 \r
488                 klass[ 'NAME' ] = displayName;\r
489                 \r
490                 if( opt_abstract ){\r
491                         classDef.isAbstract = true;\r
492                 } else\r
493                 if( opt_pool ){\r
494                         classDef.pool = [];\r
495                         classDef.live = [];\r
496                 };                      \r
497                 if( opt_final ){\r
498                         classDef.Final = true;\r
499                 } else {\r
500                         klass[ 'inherits' ] = X_Class_inherits;\r
501                 };                      \r
502                 \r
503                 X_Class_CLASS_LIST.push( klass );\r
504                 X_Class_DEF_LIST.push( classDef );                              \r
505 \r
506                 return klass;\r
507         };\r
508 \r
509 \r
510 \r
511 function X_Class_getClass( instance ){\r
512         var cList = X_Class_CLASS_LIST, i;\r
513         \r
514         if( ( i = cList.indexOf( instance.constructor ) ) !== -1 ) return cList[ i ];\r
515         if( cList.indexOf( instance ) !== -1 ) return instance;\r
516 };\r
517 \r
518 // TODO def = klass( X_Closure_COMMAND_BACK )\r
519 function X_Class_getClassDef( KlassOrInstance ){\r
520         var i = X_Class_CLASS_LIST.indexOf( KlassOrInstance );\r
521         if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );\r
522         if( i !== -1 ) return X_Class_DEF_LIST[ i ];\r
523         \r
524         if( X_Class_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
525 };\r
526 \r
527 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
528 function X_Class_override( target, src, force ){\r
529         var p;\r
530         for( p in src ){\r
531                 if( p === 'Constructor' ) continue;\r
532                 if( p === '__proto__' || p === 'prototype' || p === 'constructor' ){\r
533                         X.Logger.critical( p + ' is reserved!' );\r
534                         return;\r
535                 };\r
536                 if( force || target[ p ] === undefined ){\r
537                         target[ p ] = src[ p ];\r
538                 };\r
539         };\r
540         return target;\r
541 };\r
542 \r
543 /**\r
544  * スーパークラスか?調べます。\r
545  * @alias __ClassBase__.superClassOf\r
546  * @param klass {__ClassBase__}\r
547  * @return {boolean}\r
548  */\r
549 function X_Class_superClassOf( klass ){\r
550         var myDef      = X_Class_getClassDef( this ),\r
551                 targetDef  = X_Class_getClassDef( klass ),\r
552                 SuperClass = klass;\r
553 \r
554         if( !myDef || !targetDef || this === klass ) return false;\r
555         \r
556         while( SuperClass = X_Class_getClassDef( SuperClass ).SuperClass ){\r
557                 if( SuperClass === this ) return true;\r
558         };\r
559         \r
560         return false;\r
561 };\r
562 \r
563 /**\r
564  * サブクラスか?調べます。\r
565  * @alias __ClassBase__.subClassOf\r
566  * @type {Function}\r
567  * @param klass {__ClassBase__}\r
568  * @return {boolean}\r
569  */\r
570 function X_Class_subClassOf( klass ){\r
571         return klass && X_Class_superClassOf.call( klass, this );\r
572 };\r
573                         \r
574 /**\r
575  * サブクラスを作ります。与える引数は X_Class.create と同じです。http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
576  * @alias __ClassBase__.inherits\r
577  * @example var SubClass = SuperClass.inherits( 'Sub', X_Class.FINAL, { ... } );\r
578  * @param {string} [displayName] クラスの名前\r
579  * @param {number} [classSetting=0] X_Class.POOL_OBJECT | X_Class.FINAL など\r
580  * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと\r
581  * @return {__ClassBase__}\r
582  */\r
583 function X_Class_inherits( /* displayName, classSetting, props */ ){\r
584         var args        = X_Array_copy( arguments ),\r
585                 params      = [],\r
586                 Super       = this,\r
587                 superDef    = X_Class_getClassDef( Super ),\r
588                 displayName = args[ 0 ],\r
589                 classSetting,\r
590                 //opt_super,\r
591                 klass, def;\r
592         if( superDef.Final ) X.Logger.critical( 'X.Class inherits, Class is final!' );\r
593         \r
594         // サブクラス名\r
595         if( X_Type_isString( displayName ) ){\r
596                 args.shift();\r
597         } else {\r
598                 displayName = 'SubClass of ' + superDef.displayName;\r
599         };\r
600         params.push( displayName );\r
601         \r
602         // サブクラス設定\r
603         classSetting = args[ 0 ];\r
604         if( X_Type_isNumber( classSetting ) ){\r
605                 args.shift();\r
606         } else {\r
607                 // クラス設定がない場合、親からコピーして、Abstract flag は落とす??\r
608                 classSetting = superDef.setting;// &= ~X_Class.ABSTRACT;\r
609         };\r
610 \r
611         params.push( classSetting );\r
612 \r
613         // サブクラスのシャドウ\r
614         if( args[ 0 ] && X_Class_getClass( args[ 0 ] ) ){\r
615                 params.push( args.shift() );\r
616         };\r
617         \r
618         /* props 未定義でも可 */\r
619         params.push( args[ 0 ] );\r
620         \r
621         // 継承クラスの作成\r
622         if( X_Class_useObjectCreate ){\r
623                 X_Class_traits = Object.create( Super.prototype );\r
624         } else\r
625         if( X_Class_use_proto_ ){\r
626                 X_Class_traits = Super.prototype;\r
627         } else {\r
628                 X_Class_traits = new Super( X_Closure_COMMAND_DROP );\r
629         };\r
630         klass  = X_Class_create.apply( X.Class, params );\r
631         X_Class_traits = null;\r
632         \r
633         def    = X_Class_getClassDef( klass );\r
634         // 継承用プロパティを控える\r
635         def.SuperClass       = Super;\r
636         //def.SuperProto       = Super.prototype;\r
637         //def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor;\r
638         \r
639         return klass;\r
640 };\r
641         \r
642 /*\r
643  * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
644  * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
645  */\r
646 function X_Class_actualConstructor( f, args ){\r
647         var klass    = f.klass,\r
648                 def      = f.classDef,\r
649                 instance, obj;\r
650 \r
651         if( def.isAbstract ){\r
652                 X.Logger.critical( 'AbstractClass!' );\r
653                 return;\r
654         };\r
655         \r
656         instance = def.pool && def.pool.length ?\r
657                                         def.pool.pop() :\r
658                                 X_Class_useObjectCreate ?\r
659                                         Object.create( klass.prototype ) :\r
660                                         new klass( X_Closure_COMMAND_DROP );\r
661 \r
662         def.live && def.live.push( instance );\r
663 \r
664         if( X_Class_constructorFix && instance.constructor !== klass ){\r
665                 console.log( '------- constructor の不一致!' ); // Android2.3.7\r
666                 instance.constructor = klass;\r
667         };\r
668 \r
669         obj = def.Constructor ?\r
670                         def.Constructor.apply( instance, args ) :\r
671                         def.SuperClass && instance[ 'Super' ].apply( instance, args );\r
672 \r
673         if( obj !== instance && ( X_Type_isObject( obj ) || X_Type_isFunction( obj ) ) ){ // Class\r
674                 instance[ 'kill' ]();\r
675                 return obj;\r
676         };\r
677         \r
678         return instance;\r
679 };\r
680 \r
681 console.log( 'X.Core.Class' );\r