2 * Class を定義し システムの管理下に置く.
\r
3 * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.
\r
4 * 1. X.Class.create( opt_settings, opt_name, opt_privateClass, opt_props ) でクラスを登録.
\r
5 * 2. コンストラクタ となるメソッドは、opt_props 内の Constructor : function( arg ){ ... }, に書く.
\r
6 * 3. 通常通り new で インスタンス生成
\r
7 * 4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.
\r
8 * 5. pool が有効の場合、new で pool されたインスタンスが返される.
\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_UA.OperaMobile && !X_UA.OperaTablet && !!X.emptyFunction.prototype.__proto__,
\r
26 // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を使わないと動作,,,
\r
29 * X.Class.create で定義されたクラスのインスタンスが共通で備えるメソッド を格納
\r
33 X_Class_CommonProps =
\r
38 * TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ
\r
41 var instance = this,
\r
42 klass = X_Class_getClass( instance ),
\r
43 def = X_Class_getClassDef( klass ),
\r
45 if( def.isPrivate && !X_Class_killPrivateFlag ){
\r
46 X.Logger.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );
\r
49 X_Class_killPrivateFlag = false; // instance.kill() 内で PrivateInstance.kill() を防ぐため
\r
51 // X.EventDispatcher とそのサブクラスは kill() が呼ばれた通知を発行する。
\r
52 // X.Event.BEFORE_KILL_INSTANCE はキャンセル可能(private な class は不可)
\r
53 // X.Event.KILL_INSTANCE は、プロパティやイベントリスナの削除直前に発行
\r
54 // X.Event.KILL_INSTANCE_CANCELED は kill() がキャンセルされた場合に発行。また dispatchループ中にkill()が呼ばれると一旦キャンセルされ発行。
\r
55 // (flagを立ててdispatchの終わりにkillする)
\r
56 if( this.instanceOf( X.EventDispatcher ) ){
\r
57 if( !def.isPrivate ){
\r
58 if( this[ '_listeners' ] && this[ '_listeners' ]._dispatching ){
\r
59 this.dispatch( X.Event.BEFORE_KILL_INSTANCE );
\r
60 this[ '_listeners' ]._killReserved = true;
\r
61 this.dispatch( X.Event.KILL_INSTANCE_CANCELED );
\r
64 if( this.dispatch( X.Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){
\r
65 this.dispatch( X.Event.KILL_INSTANCE_CANCELED );
\r
69 this.dispatch( X.Event.BEFORE_KILL_INSTANCE );
\r
71 this.dispatch( X.Event.KILL_INSTANCE );
\r
72 this._listeners && X_EventDispatcher_systemUnlisten( this ); //.unlisten();
\r
75 for( p in instance ){
\r
76 if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;
\r
77 delete instance[ p ];
\r
80 def.live && def.live.splice( def.live.indexOf( instance ), 1 );
\r
81 def.pool[ def.pool.length ] = instance;
\r
83 if( def.privateClass ){
\r
84 i = def.userList.indexOf( instance );
\r
86 data = X_Class_getPrivate( instance );
\r
87 X_Class_killPrivateFlag = true;
\r
88 if( data[ '_listeners' ] && data[ '_listeners' ]._dispatching && data.instanceOf( X.EventDispatcher ) ){
\r
89 data[ '_listeners' ]._killReserved = true;
\r
93 def.dataList.splice( i, 1 );
\r
94 def.userList.splice( i, 1 );
\r
99 /* クラス定義を辿ってスーパークラスのコンストラクタを探す。
\r
100 * 呼び出したコンストラクタは配列に控える。
\r
101 * さらに呼ばれた場合、配列を元にさらに奥のコンストラクタを取得
\r
102 * TODO 現在 new しているインスタンスを保持してチェックする
\r
104 Super : function(){
\r
106 i = X_Class_CALLING_SUPER.indexOf( sClass ),
\r
108 l, sList, def, sConst, ret;
\r
111 X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass;
\r
112 X_Class_CALL_SUPER_STACK[ l ] = sList = [];
\r
114 sList = X_Class_CALL_SUPER_STACK[ i ];
\r
118 def = X_Class_getClassDef( sClass );
\r
119 sClass = def.SuperClass;
\r
120 sConst = def.SuperConstructor;
\r
121 if( sConst && sList[ ++n ] !== sConst ){
\r
122 sList[ n ] = sConst;
\r
123 ret = sConst.apply( this, arguments );
\r
125 if( !sList.length ){
\r
126 X_Class_CALLING_SUPER.splice( i, 1 );
\r
127 X_Class_CALL_SUPER_STACK.splice( i, 1 );
\r
132 console.log( 'スーパークラスのコンストラクタが見つかりません' );
\r
136 * func について、親クラスで設定されている同名の関数メンバーを呼び出す
\r
137 * 2つ以上の異なる名前で同じ関数がメンバーだった場合、失敗します
\r
138 * 例) this.superCall( arguments.callee, param0, param1, ... )
\r
140 superCall : function( func /* ...args */ ){
\r
143 name, p, sFunc, hit = false;
\r
144 if( X.Type.isFunction( func ) ){
\r
146 if( this[ p ] === func ){
\r
151 if( !name ) return;
\r
156 if( X_EMPTY_OBJECT[ name ] ) return;
\r
159 def = X_Class_getClassDef( sClass );
\r
160 sClass = def.SuperClass;
\r
161 sFunc = sClass.prototype[ name ];
\r
162 if( sFunc === func ){
\r
163 hit = true; // 現在の関数にヒット
\r
165 if( hit && X_Object_inObject( name, this ) ){
\r
166 if( X.Type.isFunction( sFunc ) ){
\r
167 switch( args.length ){
\r
169 return sFunc.call( this );
\r
171 return sFunc.call( this, args[ 1 ] );
\r
173 return sFunc.call( this, args[ 1 ], args[ 2 ] );
\r
175 return sFunc.call( this, args[ 1 ], args[ 2 ], args[ 3 ] );
\r
177 args = X.Object.cloneArray( args );
\r
179 return sFunc.apply( this, args );
\r
188 * TODO instanceof に対応したブラウザはそちらを使用
\r
190 instanceOf : function( klass ){
\r
192 if( this.constructor === klass ) return true;
\r
193 while( Super = X_Class_getClassDef( Super ).SuperClass ){
\r
194 if( Super === klass ) return true;
\r
200 // ------------------------------------------------------------------------- //
\r
201 // --- interface ----------------------------------------------------------- //
\r
202 // ------------------------------------------------------------------------- //
\r
210 * インスタンスは破棄時(this.kill())に回収され、次回の new MyClass() 時に再利用されます。
\r
211 * @memberof X.Class */
\r
215 * 定義するクラスは抽象クラスになります。new AbstractClass() とするとエラーになります。
\r
216 * @memberof X.Class */
\r
220 /** @memberof X.Class */
\r
222 /** @memberof X.Class */
\r
224 /** @memberof X.Class */
\r
226 /** @memberof X.Class */
\r
227 SINGLETON : 32, // 未実装
\r
229 create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){
\r
230 var args = X_Object_cloneArray( arguments ),
\r
231 displayName = args[ 0 ],
\r
233 opt_pool, opt_abstract, opt_final, opt_private,
\r
237 classDef = {}, hash;
\r
238 if( X.Type.isString( displayName ) === true ){
\r
239 classDef.displayName = displayName;
\r
244 classDef.setting = classSetting = args[ 0 ];
\r
245 if( X.Type.isNumber( classSetting ) ){
\r
246 opt_pool = !!( classSetting & X.Class.POOL_OBJECT );
\r
247 opt_abstract = !!( classSetting & X.Class.ABSTRACT );
\r
248 opt_final = !!( classSetting & X.Class.FINAL );
\r
249 opt_private = !!( classSetting & X.Class.PRIVATE_DATA );
\r
250 if( opt_final && opt_abstract ){
\r
251 X.Logger.critical( 'final & Abstract!' );
\r
256 classDef.setting = 0;
\r
260 if( X_Class_PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){
\r
261 privateDef = X_Class_getClassDef( args[ 0 ] );
\r
262 if( privateDef.isPrivate !== true ){
\r
263 X.Logger.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );
\r
266 if( privateDef.Abstract === true ){
\r
267 X.Logger.critical( 'PrivateClass is Abstract!' );
\r
270 classDef.privateClass = args.shift();
\r
275 if( !X.Type.isObject( props ) ){
\r
276 // サブクラスの場合、クラス定義の上書きがなくても作成可能
\r
277 // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能
\r
278 //if( !X_Class_traits ){
\r
279 // X.Logger.critical( 'No Class Def!' );
\r
284 if( props.Constructor && X.Type.isFunction( props.Constructor ) ){
\r
285 classDef.Constructor = props.Constructor;
\r
288 klass = X_Callback_actualClosure( hash = { _ : X_Class_actualConstructor } ); // TODO hash = classDef
\r
290 klass.superClassOf = X_Class_superClassOf;
\r
291 klass.subClassOf = X_Class_subClassOf;
\r
293 if( X_Class_useObjectCreate ){
\r
294 klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false );
\r
295 klass.prototype.constructor = klass;
\r
297 if( X_Class_use_proto_ ){
\r
298 X_Class_override( klass.prototype, props, true );
\r
299 if( X_Class_traits ){
\r
300 klass.prototype.__proto__ = X_Class_traits;
\r
302 X_Class_override( klass.prototype, X_Class_CommonProps, false );
\r
305 klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false );
\r
306 klass.prototype.constructor = klass;
\r
308 klass.name = displayName;
\r
310 if( opt_abstract ){
\r
311 classDef.Abstract = true;
\r
314 classDef.pool = [];
\r
315 if( opt_private === false ) classDef.live = [];
\r
318 classDef.Final = true;
\r
320 klass.inherits = X_Class_inherits;
\r
323 if( classDef.privateClass ){
\r
324 X.Logger.critical( 'Private Data Class has no PrivateClass!' );
\r
327 classDef.isPrivate = true;
\r
328 X_Class_PRIVATE_CLASS_LIST.push( klass );
\r
329 X_Class_PRIVATE_DEF_LIST.push( classDef );
\r
331 X_Class_CLASS_LIST.push( klass );
\r
332 X_Class_DEF_LIST.push( classDef );
\r
337 _newPrivate : X_Class_newPrivate,
\r
339 _getPrivate : X_Class_getPrivate
\r
343 // ------------------------------------------------------------------------- //
\r
344 // --- implements ---------------------------------------------------------- //
\r
345 // ------------------------------------------------------------------------- //
\r
346 function X_Class_getClass( instance ){
\r
347 var cList = X_Class_CLASS_LIST,
\r
351 klass = cList[ --i ];
\r
352 if( instance.constructor === klass ) return klass;
\r
354 cList = X_Class_PRIVATE_CLASS_LIST;
\r
357 klass = cList[ --i ];
\r
358 if( instance.constructor === klass ) return klass;
\r
361 if( cList.indexOf( instance ) !== -1 ) return instance;
\r
362 if( X_Class_CLASS_LIST.indexOf( instance ) !== -1 ) return instance;
\r
365 function X_Class_getClassDef( KlassOrInstance ){
\r
366 var i = X_Class_CLASS_LIST.indexOf( KlassOrInstance );
\r
367 if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );
\r
368 if( i !== -1 ) return X_Class_DEF_LIST[ i ];
\r
370 i = X_Class_PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );
\r
371 if( i === -1 ) i = X_Class_PRIVATE_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) );
\r
372 if( i !== -1 ) return X_Class_PRIVATE_DEF_LIST[ i ];
\r
374 if( X_Class_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;
\r
375 if( X_Class_PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;
\r
378 function X_Class_newPrivate( /* instance, args */ ){
\r
379 var args = X_Object_cloneArray( arguments ),
\r
380 user = args.shift(),
\r
381 def = X_Class_getClassDef( user ),
\r
382 privateClass = def.privateClass,
\r
383 privateDef = X_Class_getClassDef( privateClass ),
\r
385 if( def.userList ){
\r
386 i = def.userList.indexOf( user );
\r
392 X.Logger.critical( 'PrivateData already exist!' );
\r
395 if( privateDef._tempUser ){
\r
396 X.Logger.critical( 'newPrivate を連続呼び出しされたところ破綻' );
\r
399 privateDef._tempUser = user;
\r
400 return X_Class_actualConstructor( privateClass( X_Closure_COMMAND_BACK ), args );// privateClass.__new( args );
\r
403 function X_Class_getPrivate( instance ){
\r
404 var def = X_Class_getClassDef( instance ),
\r
405 i = def.userList.indexOf( instance );
\r
406 if( i !== -1 ) return def.dataList[ i ];
\r
409 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */
\r
410 function X_Class_override( target, src, force ){
\r
413 if( p === 'Constructor' ) continue;
\r
414 if( p === '__proto__' || p === 'prototype' || p === 'constructor' ){
\r
415 X.Logger.critical( p + ' is reserved!' );
\r
418 if( force || target[ p ] === void 0 ){
\r
419 target[ p ] = src[ p ];
\r
425 function X_Class_superClassOf( klass ){
\r
426 var myDef = X_Class_getClassDef( this ),
\r
427 targetDef = X_Class_getClassDef( klass ),
\r
428 SuperClass = klass;
\r
430 if( !myDef || !targetDef || this === klass ) return false;
\r
432 while( SuperClass = X_Class_getClassDef( SuperClass ).SuperClass ){
\r
433 if( SuperClass === this ) return true;
\r
439 function X_Class_subClassOf( klass ){
\r
440 return X_Class_superClassOf.call( klass, this );
\r
444 * var subClass = superClass.inherits( ... )
\r
445 * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002
\r
447 function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){
\r
448 var args = X_Object_cloneArray( arguments ),
\r
451 superDef = X_Class_getClassDef( Super ),
\r
452 displayName = args[ 0 ],
\r
456 if( superDef.Final ) X.Logger.critical( 'X.Class inherits, Class is final!' );
\r
459 if( X.Type.isString( displayName ) ){
\r
462 displayName = 'SubClass of ' + superDef.displayName;
\r
464 params.push( displayName );
\r
467 classSetting = args[ 0 ];
\r
468 if( X.Type.isNumber( classSetting ) ){
\r
471 // クラス設定がない場合、親からコピーして、Abstract flag は落とす??
\r
472 classSetting = superDef.setting;// &= ~X.Class.ABSTRACT;
\r
474 if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA;
\r
475 //opt_super = !!( classSetting & X.Class.SUPER_ACCESS );
\r
476 params.push( classSetting );
\r
479 if( args[ 0 ] && X_Class_getClass( args[ 0 ] ) ){
\r
480 params.push( args.shift() );
\r
482 if( superDef.privateClass ){
\r
483 params.push( superDef.privateClass );
\r
487 params.push( args[ 0 ] );
\r
490 if( X_Class_useObjectCreate ){
\r
491 X_Class_traits = Object.create( Super.prototype );
\r
493 if( X_Class_use_proto_ ){
\r
494 X_Class_traits = Super.prototype;
\r
496 X_Class_traits = new Super( X_Closure_COMMAND_DROP );
\r
498 klass = X.Class.create.apply( X.Class, params );
\r
499 X_Class_traits = null;
\r
501 def = X_Class_getClassDef( klass );
\r
503 //if( opt_super === true ){
\r
504 //def.superAccess = true;
\r
505 def.SuperClass = Super;
\r
506 def.SuperProto = Super.prototype;
\r
507 def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor;
\r
509 // def.SuperClass = Super; // instanceOf() で親クラスを調べる!
\r
516 * new の実体.コンストラクタの機能は instance.Constructor に書く.
\r
517 * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる
\r
519 function X_Class_actualConstructor( f, args ){
\r
521 def = X_Class_getClassDef( klass ),
\r
522 dataUser = def._tempUser,
\r
525 if( def.Abstract ){
\r
526 X.Logger.critical( 'AbstractClass!' );
\r
529 if( def.isPrivate && !dataUser ){
\r
530 X.Logger.critical( 'use myClass.newPrivate( instance, ...args )!' );
\r
534 instance = def.pool && def.pool.length > 0 ?
\r
536 X_Class_useObjectCreate ?
\r
537 Object.create( klass.prototype ) :
\r
538 new klass( X_Closure_COMMAND_DROP );
\r
540 if( def.isPrivate ){
\r
541 userDef = X_Class_getClassDef( dataUser );
\r
542 userDef.dataList.push( instance );
\r
543 userDef.userList.push( dataUser );
\r
544 instance.User = dataUser;
\r
545 def._tempUser = null;
\r
547 def.live && def.live.push( instance );
\r
550 obj = def.Constructor ?
\r
551 def.Constructor.apply( instance, args ) :
\r
552 def.SuperConstructor &&
\r
553 def.SuperConstructor.apply( instance, args );
\r
554 if( ( X.Type.isObject( obj ) && obj !== instance ) || X.Type.isFunction( obj ) ){ // Class
\r
561 console.log( 'X.Core.Class' );
\r