OSDN Git Service

8a09da727dcf5b60630cbd271eb9d5b85c05806c
[pettanr/clientJs.git] / 0.6.x / js / 01_core / 11_XClass.js
1 /**\r
2  * Class を定義し システムの管理下に置く.\r
3  * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.\r
4  *  1. X.Class.create( opt_settings, opt_name, opt_privateClass, opt_props ) でクラスを登録.\r
5  *  2. コンストラクタ となるメソッドは、Constructor : function( arg ){ ... }, に書く.\r
6  *  3. 通常通り new で インスタンス生成\r
7  *  4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.\r
8  *  5. pool が有効の場合、new で pool されたインスタンスが返される.\r
9  *  6. \r
10  * \r
11  */\r
12 \r
13 // ------------------------------------------------------------------------- //\r
14 // ------------ local variables -------------------------------------------- //\r
15 // ------------------------------------------------------------------------- //\r
16 var X_Class_CLASS_LIST         = [],\r
17         X_Class_DEF_LIST           = [],\r
18         X_Class_PRIVATE_CLASS_LIST = [],\r
19         X_Class_PRIVATE_DEF_LIST   = [],\r
20         X_Class_CALLING_SUPER      = [],\r
21         X_Class_CALL_SUPER_STACK   = [],\r
22         X_Class_killPrivateFlag    = false,\r
23         X_Class_traits             = null,\r
24         X_Class_useObjectCreate    = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf\r
25         X_Class_use_proto_         = !!X.emptyFunction.prototype.__proto__;\r
26 \r
27 /* \r
28  * X.Class.create で作られたクラスのインスタンスが共通で備えるメソッド \r
29  */\r
30 var X_Class_CommonProps = {\r
31         kill : function(){\r
32                 var instance = this,\r
33                         klass    = X_Class_getClass( instance ),\r
34                         def      = X_Class_getClassDef( klass ),\r
35                         data, p, i;\r
36                 if( def.isPrivate && !X_Class_killPrivateFlag ){\r
37                         X.Logger.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );\r
38                         return;\r
39                 };\r
40                 X_Class_killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため\r
41                 \r
42                 // onKill() === false の場合、kill のキャンセル\r
43                 // private      は false での キャンセル は無視される\r
44                 \r
45                 if( this.instanceOf( X.EventDispatcher ) ){\r
46                         //console.log( 'this.instanceOf( X.EventDispatcher )! ' + this._dispatching );\r
47                         if( !def.isPrivate ){\r
48                                 if( this._dispatching ){\r
49                                         this.dispatch( X.Event.BEFORE_KILL_INSTANCE );\r
50                                         this._killReserved = true;\r
51                                         this.dispatch( X.Event.KILL_INSTANCE_CANCELED );\r
52                                         return;\r
53                                 } else\r
54                                 if( this.dispatch( X.Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){\r
55                                         this.dispatch( X.Event.KILL_INSTANCE_CANCELED );\r
56                                         return;\r
57                                 };\r
58                         } else {\r
59                                 this.dispatch( X.Event.BEFORE_KILL_INSTANCE );  \r
60                         };\r
61                         this.dispatch( X.Event.KILL_INSTANCE );\r
62                         this._listeners && X_EventDispatcher_systemUnlisten( this ); //.unlisten();\r
63                 } else\r
64                 if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){\r
65                         return;\r
66                 };\r
67                 \r
68                 for( p in instance ){\r
69                         if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;\r
70                         delete instance[ p ];\r
71                 };\r
72                 if( def.pool ){\r
73                         def.live && def.live.splice( def.live.indexOf( instance ), 1 );\r
74                         def.pool[ def.pool.length ] = instance;\r
75                 };\r
76                 if( def.privateClass ){\r
77                         i = def.userList.indexOf( instance );\r
78                         if( i !== -1 ){\r
79                                 data = X_Class_getPrivate( instance );\r
80                                 X_Class_killPrivateFlag = true;\r
81                                 if( data._dispatching && data.instanceOf( X.EventDispatcher ) ){\r
82                                         data._killReserved = true;\r
83                                 } else {\r
84                                         data.kill();\r
85                                 };\r
86                                 def.dataList.splice( i, 1 );\r
87                                 def.userList.splice( i, 1 );\r
88                         };\r
89                 };\r
90         },\r
91         \r
92         // TODO Super\r
93         // superCall\r
94         \r
95         instanceOf : function( klass ){\r
96                 var Super = this;\r
97                 if( this.constructor === klass ) return true;\r
98                 while( Super = X_Class_getClassDef( Super ).SuperClass ){\r
99                         if( Super === klass ) return true;\r
100                 };\r
101                 return false;\r
102         }\r
103 };\r
104 // ------------------------------------------------------------------------- //\r
105 // --- interface ----------------------------------------------------------- //\r
106 // ------------------------------------------------------------------------- //\r
107 X.Class = {\r
108         \r
109         POOL_OBJECT  :  1,\r
110         ABSTRACT     :  2,\r
111         FINAL        :  4,\r
112         SUPER_ACCESS :  8,\r
113         PRIVATE_DATA : 16,\r
114         \r
115         SINGLETON    : 32, // 未実装\r
116         \r
117         create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
118                 var args        = X_Object_cloneArray( arguments ),\r
119                         displayName = args[ 0 ],\r
120                         classSetting,\r
121                         opt_pool, opt_abstract, opt_final, opt_private,\r
122                         privateDef,\r
123                         props,\r
124                         klass,\r
125                         classDef = {}, hash;\r
126                 if( X.Type.isString( displayName ) === true ){\r
127                         classDef.displayName = displayName;\r
128                         args.shift();\r
129                 };\r
130                 \r
131                 // クラス設定\r
132                 classDef.setting = classSetting = args[ 0 ];\r
133                 if( X.Type.isNumber( classSetting ) ){\r
134                         opt_pool     = !!( classSetting & X.Class.POOL_OBJECT  );\r
135                         opt_abstract = !!( classSetting & X.Class.ABSTRACT     );\r
136                         opt_final    = !!( classSetting & X.Class.FINAL        );\r
137                         opt_private  = !!( classSetting & X.Class.PRIVATE_DATA );\r
138                         if( opt_final && opt_abstract ){\r
139                                 X.Logger.critical( 'final & Abstract!' );\r
140                                 return;\r
141                         };      \r
142                         args.shift();\r
143                 } else {\r
144                         classDef.setting = 0;\r
145                 };\r
146                 \r
147                 // シャドウクラス\r
148                 if( X_Class_PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){\r
149                         privateDef = X_Class_getClassDef( args[ 0 ] );\r
150                         if( privateDef.isPrivate !== true ){\r
151                                 X.Logger.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );\r
152                                 return;\r
153                         } else\r
154                         if( privateDef.Abstract === true ){\r
155                                 X.Logger.critical( 'PrivateClass is Abstract!' );\r
156                                 return;\r
157                         };\r
158                         classDef.privateClass = args.shift();\r
159                 };\r
160                 \r
161                 // インスタンスのメンバー\r
162                 props = args[ 0 ];\r
163                 if( !X.Type.isObject( props ) ){\r
164                         // サブクラスの場合、クラス定義の上書きがなくても作成可能\r
165                         // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能\r
166                         //if( !X_Class_traits ){\r
167                         //      X.Logger.critical( 'No Class Def!' );\r
168                         //      return;\r
169                         //};\r
170                         props = {};\r
171                 } else\r
172                 if( props.Constructor && X.Type.isFunction( props.Constructor ) ){\r
173                         classDef.Constructor = props.Constructor;\r
174                 };\r
175 \r
176                 // TODO use X.Function\r
177                 klass  = X_Closure_actualClosure( hash = { _ : X_Class_actualConstructor } );//new Function( 'var a=arguments,f=a.callee;if(f.__new)return f.__new(a)' );\r
178                 hash.c = klass;\r
179                 //klass.__new = X_Class_actualConstructor;\r
180                 klass.superClassOf = X_Class_superClassOf;\r
181                 klass.subClassOf   = X_Class_subClassOf;\r
182                 \r
183                 if( X_Class_useObjectCreate ){\r
184                         klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false );\r
185                         klass.prototype.constructor = klass;\r
186                 } else\r
187                 if( X_Class_use_proto_ ){\r
188                         X_Class_override( klass.prototype, props, true );\r
189                         if( X_Class_traits ){\r
190                                 klass.prototype.__proto__ = X_Class_traits;\r
191                         } else {\r
192                                 X_Class_override( klass.prototype, X_Class_CommonProps, false );\r
193                         };\r
194                 } else {\r
195                         klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false );\r
196                         klass.prototype.constructor = klass;\r
197                 };\r
198                 klass.name = displayName;\r
199                 \r
200                 if( opt_abstract ){\r
201                         classDef.Abstract = true;\r
202                 } else\r
203                 if( opt_pool ){\r
204                         classDef.pool = [];\r
205                         if( opt_private === false ) classDef.live = [];\r
206                 };                      \r
207                 if( opt_final ){\r
208                         classDef.Final = true;\r
209                 } else {\r
210                         klass.inherits = X_Class_inherits;\r
211                 };                      \r
212                 if( opt_private ){\r
213                         if( classDef.privateClass ){\r
214                                 X.Logger.critical( 'Private Data Class has no PrivateClass!' );\r
215                                 return;\r
216                         };\r
217                         classDef.isPrivate = true;\r
218                         X_Class_PRIVATE_CLASS_LIST.push( klass );\r
219                         X_Class_PRIVATE_DEF_LIST.push( classDef );\r
220                 } else {\r
221                         X_Class_CLASS_LIST.push( klass );\r
222                         X_Class_DEF_LIST.push( classDef );                              \r
223                 };\r
224                 return klass;\r
225         },\r
226         \r
227         _getClass    : X_Class_getClass,\r
228         \r
229         _getClassDef : X_Class_getClassDef,\r
230         \r
231         _newPrivate  : X_Class_newPrivate,\r
232         \r
233         _getPrivate  : X_Class_getPrivate,\r
234         \r
235         _override    : X_Class_override\r
236         \r
237 };\r
238 \r
239 // ------------------------------------------------------------------------- //\r
240 // --- implements ---------------------------------------------------------- //\r
241 // ------------------------------------------------------------------------- //\r
242 function X_Class_getClass( instance ){\r
243         var cList    = X_Class_CLASS_LIST,\r
244                 i        = cList.length,\r
245                 klass;\r
246         for( ; i; ){\r
247                 klass = cList[ --i ];\r
248                 if( instance.constructor === klass ) return klass;\r
249         };\r
250         cList = X_Class_PRIVATE_CLASS_LIST;\r
251         i     = cList.length;\r
252         for( ; i; ){\r
253                 klass = cList[ --i ];\r
254                 if( instance.constructor === klass ) return klass;\r
255         };\r
256         \r
257         if( cList.indexOf( instance ) !== -1 ) return instance;\r
258         if( X_Class_CLASS_LIST.indexOf( instance ) !== -1 ) return instance;\r
259 };\r
260 \r
261 function X_Class_getClassDef( KlassOrInstance ){\r
262         var i = X_Class_CLASS_LIST.indexOf( KlassOrInstance );\r
263         if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );\r
264         if( i !== -1 ) return X_Class_DEF_LIST[ i ];\r
265         \r
266         i = X_Class_PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );\r
267         if( i === -1 ) i = X_Class_PRIVATE_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );\r
268         if( i !== -1 ) return X_Class_PRIVATE_DEF_LIST[ i ];\r
269         \r
270         if( X_Class_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
271         if( X_Class_PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;\r
272 };\r
273 \r
274 function X_Class_newPrivate( /* instance, args */ ){\r
275         var args         = X_Object_cloneArray( arguments ),\r
276                 user         = args.shift(),\r
277                 def          = X_Class_getClassDef( user ),\r
278                 privateClass = def.privateClass,\r
279                 privateDef   = X_Class_getClassDef( privateClass ),\r
280                 i            = -1;\r
281         if( def.userList ){\r
282                 i = def.userList.indexOf( user );\r
283         } else {\r
284                 def.userList = [];\r
285                 def.dataList = [];\r
286         };\r
287         if( i !== -1 ){\r
288                 X.Logger.critical( 'PrivateData already exist!' );\r
289                 return;\r
290         };\r
291         if( privateDef._tempUser ){\r
292                 X.Logger.critical( 'newPrivate を連続呼び出しされたところ破綻' );\r
293                 return;\r
294         };\r
295         privateDef._tempUser = user;\r
296         return X_Class_actualConstructor( privateClass( X_Closure_COMMAND_BACK ), args );// privateClass.__new( args );\r
297 };\r
298 \r
299 function X_Class_getPrivate( instance ){\r
300         var def = X_Class_getClassDef( instance ),\r
301                 i   = def.userList.indexOf( instance );\r
302         if( i !== -1 ) return def.dataList[ i ];\r
303 };\r
304 \r
305 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */\r
306 function X_Class_override( target, src, force ){\r
307         var p;\r
308         for( p in src ){\r
309                 if( p === 'Super' || p === 'SuperConstructor' || p === '__proto__' || p === 'prototype' || p === 'constructor' ){\r
310                         X.Logger.critical( 'Super & SuperConstructor is reserved!' );\r
311                         return;\r
312                 };\r
313                 if( force || target[ p ] === void 0 ){\r
314                         target[ p ] = src[ p ];\r
315                 };\r
316         };\r
317         return target;\r
318 };\r
319 \r
320 function X_Class_superClassOf( klass ){\r
321         var myDef      = X_Class_getClassDef( this ),\r
322                 targetDef  = X_Class_getClassDef( klass ),\r
323                 SuperClass = klass;\r
324 \r
325         if( !myDef || !targetDef || this === klass ) return false;\r
326         \r
327         while( SuperClass = X_Class_getClassDef( SuperClass ).SuperClass ){\r
328                 if( SuperClass === this ) return true;\r
329         };\r
330         \r
331         return false;\r
332 };\r
333 \r
334 function X_Class_subClassOf( klass ){\r
335         return X_Class_superClassOf.call( klass, this );\r
336 };\r
337         \r
338 /* サブクラスを作るメソッド  \r
339  * var subClass = superClass.inherits( ... ) \r
340  * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002\r
341  */\r
342 function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){\r
343         var args        = X_Object_cloneArray( arguments ),\r
344                 params      = [],\r
345                 Super       = this,\r
346                 superDef    = X_Class_getClassDef( Super ),\r
347                 displayName = args[ 0 ],\r
348                 classSetting,\r
349                 opt_super,\r
350                 klass, def;\r
351         if( superDef.Final ) X.Logger.critical( 'X.Class inherits, Class is final!' );\r
352         \r
353         // サブクラス名\r
354         if( X.Type.isString( displayName ) ){\r
355                 args.shift();\r
356         } else {\r
357                 displayName = 'SubClass of ' + superDef.displayName;\r
358         };\r
359         params.push( displayName );\r
360         \r
361         // サブクラス設定\r
362         classSetting = args[ 0 ];\r
363         if( X.Type.isNumber( classSetting ) ){\r
364                 args.shift();\r
365         } else {\r
366                 // クラス設定がない場合、親からコピーして、Abstract flag は落とす??\r
367                 classSetting = superDef.setting;// &= ~X.Class.ABSTRACT;\r
368         };\r
369         if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA;\r
370         opt_super = !!( classSetting & X.Class.SUPER_ACCESS );\r
371         params.push( classSetting );\r
372 \r
373         // サブクラスのシャドウ\r
374         if( args[ 0 ] && X_Class_getClass( args[ 0 ] ) ){\r
375                 params.push( args.shift() );\r
376         } else\r
377         if( superDef.privateClass ){\r
378                 params.push( superDef.privateClass );\r
379         };\r
380         params.push( args[ 0 ] ); /* props サブクラスでは未定義でも可 */\r
381         \r
382         // 継承クラスの作成\r
383         if( X_Class_useObjectCreate ){\r
384                 X_Class_traits = Object.create( Super.prototype );\r
385         } else\r
386         if( X_Class_use_proto_ ){\r
387                 X_Class_traits = Super.prototype;\r
388         } else {\r
389                 //Super.__new = null;\r
390                 X_Class_traits = new Super( X_Closure_COMMAND_DROP );\r
391                 //Super.__new = X_Class_actualConstructor;                      \r
392         };\r
393         klass  = X.Class.create.apply( X.Class, params );\r
394         X_Class_traits = null;\r
395         \r
396         def    = X_Class_getClassDef( klass );\r
397         // 継承用プロパティを控える\r
398         if( opt_super === true ){\r
399                 def.superAccess = true;\r
400                 def.SuperClass  = Super;\r
401                 def.SuperProto  = Super.prototype;\r
402                 def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor;\r
403         } else {\r
404                 def.SuperClass = Super; // instanceOf() で親クラスを調べる!\r
405         };\r
406         \r
407         return klass;\r
408 };\r
409         \r
410 /*\r
411  * new の実体.コンストラクタの機能は instance.Constructor に書く.\r
412  * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる\r
413  */\r
414 function X_Class_actualConstructor( obj, args ){\r
415         var klass    = obj.c,//this,\r
416                 def      = X_Class_getClassDef( klass ),\r
417                 dataUser = def._tempUser,\r
418                 instance, obj,\r
419                 userDef;\r
420         if( def.Abstract ){\r
421                 X.Logger.critical( 'AbstractClass!' );\r
422                 return;\r
423         };\r
424         if( def.isPrivate && !dataUser ){\r
425                 X.Logger.critical( 'use myClass.newPrivate( instance, ...args )!' );\r
426                 return;\r
427         };\r
428         //klass.__new = null;\r
429         instance = def.pool && def.pool.length > 0 ?\r
430                                         def.pool.pop() :\r
431                                 X_Class_useObjectCreate ?\r
432                                         Object.create( klass.prototype ) :\r
433                                         new klass( X_Closure_COMMAND_DROP );\r
434         //klass.__new = X_Class_actualConstructor;\r
435         \r
436         if( def.isPrivate ){\r
437                 userDef = X_Class_getClassDef( dataUser );\r
438                 userDef.dataList.push( instance );\r
439                 userDef.userList.push( dataUser );\r
440                 instance.User = dataUser;\r
441                 def._tempUser = null;\r
442         } else {\r
443                 def.live && def.live.push( instance );\r
444         };\r
445         if( def.superAccess ){\r
446                 // TODO klass.prototype に移動\r
447                 instance.Super = def.SuperProto;\r
448                 instance.SuperConstructor = X_Class_superConstructor;\r
449         };\r
450         obj = def.Constructor ?\r
451                         def.Constructor.apply( instance, args ) :\r
452                 def.SuperConstructor &&\r
453                         def.SuperConstructor.apply( instance, args );\r
454         if( ( X.Type.isObject( obj ) && obj !== instance ) || X.Type.isFunction( obj ) ){ // Class\r
455                 instance.kill();\r
456                 return obj;\r
457         };\r
458         return instance;\r
459 };\r
460 /*  クラス定義を辿ってスーパークラスのコンストラクタを探す。\r
461  *  呼び出したコンストラクタは配列に控える。\r
462  *  さらに呼ばれた場合、配列を元にさらに奥のコンストラクタを取得\r
463  *  TODO 現在 new しているインスタンスを保持してチェックする\r
464  */\r
465 function X_Class_superConstructor(){\r
466         var sClass = this,\r
467                 i      = X_Class_CALLING_SUPER.indexOf( sClass ),\r
468                 n      = -1,\r
469                 l, sList, def, sConst, ret;\r
470 \r
471         if( i === -1 ){\r
472                 X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass;\r
473                 X_Class_CALL_SUPER_STACK[ l ] = sList = [];\r
474         } else {\r
475                 sList = X_Class_CALL_SUPER_STACK[ i ];\r
476         };\r
477         \r
478         while( sClass ){\r
479                 def    = X_Class_getClassDef( sClass );\r
480                 sClass = def.SuperClass;\r
481                 sConst = def.SuperConstructor;\r
482                 if( sConst && sList[ ++n ] !== sConst ){\r
483                         sList[ n ] = sConst;\r
484                         ret = sConst.apply( this, arguments );\r
485                         --sList.length;\r
486                         if( !sList.length ){\r
487                                 X_Class_CALLING_SUPER.splice( i, 1 );\r
488                                 X_Class_CALL_SUPER_STACK.splice( i, 1 );\r
489                         };\r
490                         return ret;\r
491                 };\r
492         };\r
493 };\r
494 \r
495 console.log( 'X.Core.Class' );\r