OSDN Git Service

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