X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=0.6.x%2Fjs%2F01_core%2F11_XClass.js;h=e4b556aa53ab1eed7c551f6b0e88eaf7c0dd692f;hb=8e74cf066ea48ec8cf34efb2b5e84725c10c813a;hp=5222ea86afed10b2f55c1b3da25a04cdd3fecc57;hpb=57e35f063b4a70fcec59db6ec7366b43f41f0ba4;p=pettanr%2FclientJs.git diff --git a/0.6.x/js/01_core/11_XClass.js b/0.6.x/js/01_core/11_XClass.js index 5222ea8..e4b556a 100644 --- a/0.6.x/js/01_core/11_XClass.js +++ b/0.6.x/js/01_core/11_XClass.js @@ -1,105 +1,192 @@ -/** - * Class を定義し システムの管理下に置く. - * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される. - * 1. X.Class.create( opt_settings, opt_name, opt_privateClass, opt_props ) でクラスを登録. - * 2. コンストラクタ となるメソッドは、opt_props 内の Constructor : function( arg ){ ... }, に書く. - * 3. 通常通り new で インスタンス生成 - * 4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される. - * 5. pool が有効の場合、new で pool されたインスタンスが返される. - * 6. - * - */ // ------------------------------------------------------------------------- // // ------------ local variables -------------------------------------------- // // ------------------------------------------------------------------------- // -var X_Class_CLASS_LIST = [], +var + /** + * 全てのクラスのスーパークラスのようなもの。(ライブラリ内にカプセル化されているため、ユーザが触ることはありません)
+ * X.Class.create() で定義されたクラスのインスタンスが共通で備えるメソッド を確認してください。 + * @class __ClassBase__ + * @private + * @abstract + */ + __ClassBase__ = { + /** + * クラス名 + * @type {string} + */ + name : '' + }, + + X_Class_CLASS_LIST = [], X_Class_DEF_LIST = [], - X_Class_PRIVATE_CLASS_LIST = [], - X_Class_PRIVATE_DEF_LIST = [], X_Class_CALLING_SUPER = [], X_Class_CALL_SUPER_STACK = [], - X_Class_killPrivateFlag = false, X_Class_traits = null, X_Class_useObjectCreate = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf - X_Class_use_proto_ = !!X.emptyFunction.prototype.__proto__, - -/** - * X.Class.create で定義されたクラスのインスタンスが共通で備えるメソッド を格納 - * - * @class - */ -X_Class_CommonProps = + X_Class_use_proto_ = !X_UA[ 'OperaMobile' ] && !X_UA[ 'OperaTablet' ] && !!X_emptyFunction.prototype.__proto__, + // Opera Mobile 12.10 Android11 IS01 でクラスのメンバが欠落する問題に遭遇。__proto__ を使わないと動作,,, +X_Class_CommonMethods = +/** @lends __ClassBase__.prototype */ { - /* - * インスタンスの破棄。 + /** + * 全ての動的メンバを削除して、インスタンスを破棄する。
+ * インスタンスが X.EventDispatcher とそのサブクラスの場合、次の動作をする。 + *
    + *
  1. X.Event.BEFORE_KILL_INSTANCE を発火する。戻り値のビットフラグに X_Callback.PREVENT_DEFAULT が立つ場合、破棄をキャンセルし X.Event.KILL_INSTANCE_CANCELED を発火する。 + *
  2. 破棄に進む場合は、X.Event.KILL_INSTANCE を発火する。 + *
  3. dispatch 中は、インスタンスの全ての dispatch が終了するまで実際の破棄を待つ。 + *
  4. 実際の破棄では、インスタンスのメンバの削除に加えて全てのイベントリスナを解除する。 */ - kill : function(){ - var instance = this, - klass = X_Class_getClass( instance ), - def = X_Class_getClassDef( klass ), - data, p, i; - if( def.isPrivate && !X_Class_killPrivateFlag ){ - X.Logger.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' ); - return; - }; - X_Class_killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため + // TODO kill したインスタンスのイベントが残っていないか?これは開発用のみ + 'kill' : function(){ + var def, listeners, p; - // onKill() === false の場合、kill のキャンセル - // private は false での キャンセル は無視される + // TODO kill 中の kill の呼び出しを防ぐ, 破棄済のインスタンスへの kill - if( this.instanceOf( X.EventDispatcher ) ){ - //console.log( 'this.instanceOf( X.EventDispatcher )! ' + this._dispatching ); - if( !def.isPrivate ){ - if( this._dispatching ){ - this.dispatch( X.Event.BEFORE_KILL_INSTANCE ); - this._killReserved = true; - this.dispatch( X.Event.KILL_INSTANCE_CANCELED ); - return; - } else - if( this.dispatch( X.Event.BEFORE_KILL_INSTANCE ) & X.Callback.PREVENT_DEFAULT ){ - this.dispatch( X.Event.KILL_INSTANCE_CANCELED ); - return; + if( this[ 'instanceOf' ]( X_EventDispatcher ) ){ + + if( this[ 'dispatch' ]( X_EVENT_BEFORE_KILL_INSTANCE ) & X_Callback_PREVENT_DEFAULT ){ + this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE_CANCELED ); + return; + }; + + listeners = this[ '_listeners' ]; + + if( listeners && listeners[ X_LISTENERS_DISPATCHING ] ){ + listeners[ X_LISTENERS_KILL_RESERVED ] = true; + return; + }; + + // asyncDispatch の削除 + for( p in X_EventDispatcher_LAZY_TIMERS ){ + if( X_EventDispatcher_LAZY_TIMERS[ p ] === this ){ + // delete X_EventDispatcher_LAZY_TIMERS[ p ]; コレ不要 + X_Timer_remove( p ); }; - } else { - this.dispatch( X.Event.BEFORE_KILL_INSTANCE ); }; - this.dispatch( X.Event.KILL_INSTANCE ); - this._listeners && X_EventDispatcher_systemUnlisten( this ); //.unlisten(); - } else - if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){ - return; + + this[ 'dispatch' ]( X_EVENT_KILL_INSTANCE ); + listeners && X_EventDispatcher_unlistenAll( this ); }; - for( p in instance ){ - if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue; - delete instance[ p ]; - }; + X_Object_clear( this ); + + def = X_Class_getClassDef( this ); + if( def.pool ){ - def.live && def.live.splice( def.live.indexOf( instance ), 1 ); - def.pool[ def.pool.length ] = instance; + def.live.splice( def.live.indexOf( this ), 1 ); + def.pool[ def.pool.length ] = this; + }; + }, + + /** + * 関数は Constructor 内で使用します。クラス定義を辿ってスーパークラスのコンストラクタを探します。
    + * 内部的には、呼び出したコンストラクタは配列に控え(X_Class_CALLING_SUPER)、呼び出したコンストラクタ内でさらに Super が呼ばれた場合、配列を元にさらにスーパーなコンストラクタを辿ります。 + * @example Constructor : function( arg1, arg2 ){ + * this.Super( aeg1, arg2 ); + * } + * @param var_args {...?} 親コンストラクタを呼ぶ際に渡す任意の数の引数 + * @return {*} + */ + // TODO 現在 new しているインスタンスを保持してチェックする + 'Super' : function( var_args ){ + var sClass = this, + i = X_Class_CALLING_SUPER.indexOf( sClass ), + n = -1, + l, sList, def, sConst, ret; + + if( i === -1 ){ + X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass; + X_Class_CALL_SUPER_STACK[ l ] = sList = []; + } else { + sList = X_Class_CALL_SUPER_STACK[ i ]; }; - if( def.privateClass ){ - i = def.userList.indexOf( instance ); - if( i !== -1 ){ - data = X_Class_getPrivate( instance ); - X_Class_killPrivateFlag = true; - if( data._dispatching && data.instanceOf( X.EventDispatcher ) ){ - data._killReserved = true; - } else { - data.kill(); + + while( sClass ){ + def = X_Class_getClassDef( sClass ); + sClass = def.SuperClass; + sConst = def.SuperConstructor; + if( sConst && sList[ ++n ] !== sConst ){ + sList[ n ] = sConst; + ret = sConst.apply( this, arguments ); + --sList.length; + if( !sList.length ){ + X_Class_CALLING_SUPER.splice( i, 1 ); + X_Class_CALL_SUPER_STACK.splice( i, 1 ); }; - def.dataList.splice( i, 1 ); - def.userList.splice( i, 1 ); + return ret; + }; + }; + console.log( 'スーパークラスのコンストラクタが見つかりません' ); + }, + + /** + * func について、親クラスで設定されている同名の関数メンバーを呼び出す。
    + * 第一引数に関数を指定し、2つ以上の異なる名前で同じ関数がメンバーがいた場合、動作が不確実になります。
    + * 参考:ES5なJavascriptでモダンなクラス的継承&スーパー呼び出し + * @param funcNameOrFunc {Function|string} スーパークラスの関数名 または、オーバーライド済の自身の関数。 + * @param var_args {...*} オーバーライド元関数に渡す任意の数の引数 + * @example return this.superCall( arguments.callee, param0, param1, ... ); + * @return {*} オーバーライド元の関数を呼び出した戻り値。 + */ + 'superCall' : function( funcNameOrFunc, var_args ){ + var sClass = this, + args = arguments, + name, p, sFunc, hit = false; + if( X_Type_isFunction( funcNameOrFunc ) ){ + for( p in this.constructor.prototype ){ + if( this.constructor.prototype[ p ] === funcNameOrFunc ){ + name = p; + break; + }; + }; + if( !name ) return; + } else { + return; + }; + + if( X_EMPTY_OBJECT[ name ] ) return; + + while( sClass ){ + def = X_Class_getClassDef( sClass ); + sClass = def.SuperClass; + sFunc = sClass.prototype[ name ]; + if( sFunc === funcNameOrFunc ){ + hit = true; // 現在の関数にヒット + } else + if( hit && X_Object_inObject( name, this ) ){ + if( X_Type_isFunction( sFunc ) ){ + switch( args.length ){ + case 1 : + return sFunc.call( this ); + case 2 : + return sFunc.call( this, args[ 1 ] ); + case 3 : + return sFunc.call( this, args[ 1 ], args[ 2 ] ); + case 4 : + return sFunc.call( this, args[ 1 ], args[ 2 ], args[ 3 ] ); + default : + args = X_Object_cloneArray( args ); + args.shift(); + return sFunc.apply( this, args ); + }; + }; + break; }; }; }, - // TODO Super - // superCall - - instanceOf : function( klass ){ + /** + * インスタンスのクラスか?またはスーパークラスか?調べる。
    + * instanceof 構文をサポートしない環境(IE4,Mac IE5)を想定する場合、必ずこのメソッドを使用すること。
    + * クラスのインスタンスか?だけ調べたい場合は this.constructor === klass が高速。 + * @param klass {__ClassBase__} クラス定義 + * @return {boolean} + */ + // TODO instanceof に対応したブラウザはそちらを使用 + 'instanceOf' : function( klass ){ var Super = this; if( this.constructor === klass ) return true; while( Super = X_Class_getClassDef( Super ).SuperClass ){ @@ -108,53 +195,132 @@ X_Class_CommonProps = return false; } }; + // ------------------------------------------------------------------------- // // --- interface ----------------------------------------------------------- // // ------------------------------------------------------------------------- // -/** @namespace */ -X.Class = { +/* + * @enum {number} + * @const + */ +var X_Class = { + NONE : 0, + POOL_OBJECT : 1, + ABSTRACT : 2, + FINAL : 4, + SINGLETON : 8 +}; + +/** + *

    Class を定義し システムの管理下に置く。 + *

    prototype 継承のブラウザ毎の差異も吸収し、 以下から最適な方法をしてくれる。 + * + *

      + *
    1. Object.create はパフォーマンスが悪そうなので現在は使っていない。 + *
    2. SubClass.prototype.__proto__ = SuperClass.prototype; + *
    3. SubClass.prototype = new SuperClass; + *
    + * + *
      + *
    1. X.Class.create( opt_settings, opt_name, opt_props ) でクラスを登録. + *
    2. コンストラクタ となるメソッドは、opt_props 内の Constructor : function( arg ){ ... }, に書く. + *
    3. 通常通り new で インスタンス生成 + *
    4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される. + *
    5. pool が有効の場合、new で pool されたインスタンスが返される. + *
    + * @namespace X.Class + * @alias X.Class + */ +X[ 'Class' ] = /** @lends X.Class */ { + + /** + * 設定なし。 + * @const + */ + 'NONE' : X_Class.NONE, + /** * インスタンスは破棄時(this.kill())に回収され、次回の new MyClass() 時に再利用されます。 - * @memberof X.Class */ - POOL_OBJECT : 1, + * @const + */ + 'POOL_OBJECT' : X_Class.POOL_OBJECT, /** * 定義するクラスは抽象クラスになります。new AbstractClass() とするとエラーになります。 - * @memberof X.Class */ - ABSTRACT : 2, - - - /** @memberof X.Class */ - FINAL : 4, - /** @memberof X.Class */ - SUPER_ACCESS : 8, - /** @memberof X.Class */ - PRIVATE_DATA : 16, - /** @memberof X.Class */ - SINGLETON : 32, // 未実装 + * @const + */ + 'ABSTRACT' : X_Class.ABSTRACT, + + /** + * クラスの継承を禁止する。 + * @const + */ + 'FINAL' : X_Class.FINAL, + + /** + * 未実装。でも目印になるので付けておきましょう。 + * @const + */ + 'SINGLETON' : X_Class.SINGLETON, + + 'create' : X_Class_create - create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){ + // TODO collect +}; + + + +// ------------------------------------------------------------------------- // +// --- implements ---------------------------------------------------------- // +// ------------------------------------------------------------------------- // + /** + * クラスを定義する。
    + * X.Class.create() によるクラス定義は必ずしもコンストラクタ('Constructor')を必要としません。クラス定義時にコンストラクタが未設定の場合、スーパークラスがあればそのコンストラクタを使用します。 + * @alias X.Class.create + * @param {string} [displayName] クラスの名前 + * @param {number} [classSetting=0] X_Class.POOL_OBJECT | X_Class.FINAL など + * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと + * @return {__ClassBase__} + * @example var myClass = X.Class.create( + * 'myClass', + * X.Class.FINAL, + * { + * name : '', + * Constructor : function( obj ){ + * this.name = obj.name; + * }, + * getName : function(){ + * return this.name; + * }, + * setName : function(v){ + * this.name = v; + * } + * } + * ); + */ + function X_Class_create( /* displayName, classSetting, privateClass, props */ ){ var args = X_Object_cloneArray( arguments ), displayName = args[ 0 ], classSetting, - opt_pool, opt_abstract, opt_final, opt_private, + opt_pool, opt_abstract, opt_final, privateDef, props, klass, - classDef = {}, hash; - if( X.Type.isString( displayName ) === true ){ + classDef = {}, + cbHash = { proxy : X_Class_actualConstructor, classDef : classDef }; + + if( X_Type_isString( displayName ) === true ){ classDef.displayName = displayName; args.shift(); }; // クラス設定 classDef.setting = classSetting = args[ 0 ]; - if( X.Type.isNumber( classSetting ) ){ - opt_pool = !!( classSetting & X.Class.POOL_OBJECT ); - opt_abstract = !!( classSetting & X.Class.ABSTRACT ); - opt_final = !!( classSetting & X.Class.FINAL ); - opt_private = !!( classSetting & X.Class.PRIVATE_DATA ); + if( X_Type_isNumber( classSetting ) ){ + opt_pool = !!( classSetting & X_Class.POOL_OBJECT ); + opt_abstract = !!( classSetting & X_Class.ABSTRACT ); + opt_final = !!( classSetting & X_Class.FINAL ); if( opt_final && opt_abstract ){ X.Logger.critical( 'final & Abstract!' ); return; @@ -164,42 +330,29 @@ X.Class = { classDef.setting = 0; }; - // シャドウクラス - if( X_Class_PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){ - privateDef = X_Class_getClassDef( args[ 0 ] ); - if( privateDef.isPrivate !== true ){ - X.Logger.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' ); - return; - } else - if( privateDef.Abstract === true ){ - X.Logger.critical( 'PrivateClass is Abstract!' ); - return; - }; - classDef.privateClass = args.shift(); - }; - // インスタンスのメンバー props = args[ 0 ]; - if( !X.Type.isObject( props ) ){ - // サブクラスの場合、クラス定義の上書きがなくても作成可能 - // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能 - //if( !X_Class_traits ){ - // X.Logger.critical( 'No Class Def!' ); - // return; - //}; + if( !X_Type_isObject( props ) ){ + // クラスメンバ用オブジェクトが無しでもクラスは作成可能 props = {}; } else - if( props.Constructor && X.Type.isFunction( props.Constructor ) ){ - classDef.Constructor = props.Constructor; + if( props[ 'Constructor' ] ){ + //{+dev + if( !X_Type_isFunction( props[ 'Constructor' ] ) ){ + alert( '"Constructor" is not function.' ); + return; + }; + //}+dev + classDef.Constructor = props[ 'Constructor' ]; }; - klass = X_Callback_actualClosure( hash = { _ : X_Class_actualConstructor } ); // TODO hash = classDef - hash.c = klass; - klass.superClassOf = X_Class_superClassOf; - klass.subClassOf = X_Class_subClassOf; + klass = X_Callback_actualClosure( cbHash ); // TODO callbackHash を class定義の置き場所にしてしまう!なるほど… + cbHash.klass = klass; + klass[ 'superClassOf' ] = X_Class_superClassOf; + klass[ 'subClassOf' ] = X_Class_subClassOf; if( X_Class_useObjectCreate ){ - klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false ); + klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonMethods, false ); klass.prototype.constructor = klass; } else if( X_Class_use_proto_ ){ @@ -207,50 +360,36 @@ X.Class = { if( X_Class_traits ){ klass.prototype.__proto__ = X_Class_traits; } else { - X_Class_override( klass.prototype, X_Class_CommonProps, false ); + X_Class_override( klass.prototype, X_Class_CommonMethods, false ); }; } else { - klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonProps, false ); + klass.prototype = X_Class_override( X_Class_override( X_Class_traits || klass.prototype, props, true ), X_Class_CommonMethods, false ); klass.prototype.constructor = klass; }; - klass.name = displayName; + + klass[ 'name' ] = displayName; if( opt_abstract ){ classDef.Abstract = true; } else if( opt_pool ){ classDef.pool = []; - if( opt_private === false ) classDef.live = []; + classDef.live = []; }; if( opt_final ){ classDef.Final = true; } else { - klass.inherits = X_Class_inherits; + klass[ 'inherits' ] = X_Class_inherits; }; - if( opt_private ){ - if( classDef.privateClass ){ - X.Logger.critical( 'Private Data Class has no PrivateClass!' ); - return; - }; - classDef.isPrivate = true; - X_Class_PRIVATE_CLASS_LIST.push( klass ); - X_Class_PRIVATE_DEF_LIST.push( classDef ); - } else { - X_Class_CLASS_LIST.push( klass ); - X_Class_DEF_LIST.push( classDef ); - }; + + X_Class_CLASS_LIST.push( klass ); + X_Class_DEF_LIST.push( classDef ); + return klass; - }, - - _newPrivate : X_Class_newPrivate, - - _getPrivate : X_Class_getPrivate - -}; + }; + + -// ------------------------------------------------------------------------- // -// --- implements ---------------------------------------------------------- // -// ------------------------------------------------------------------------- // function X_Class_getClass( instance ){ var cList = X_Class_CLASS_LIST, i = cList.length, @@ -259,15 +398,7 @@ function X_Class_getClass( instance ){ klass = cList[ --i ]; if( instance.constructor === klass ) return klass; }; - cList = X_Class_PRIVATE_CLASS_LIST; - i = cList.length; - for( ; i; ){ - klass = cList[ --i ]; - if( instance.constructor === klass ) return klass; - }; - if( cList.indexOf( instance ) !== -1 ) return instance; - if( X_Class_CLASS_LIST.indexOf( instance ) !== -1 ) return instance; }; function X_Class_getClassDef( KlassOrInstance ){ @@ -275,60 +406,31 @@ function X_Class_getClassDef( KlassOrInstance ){ if( i === -1 ) i = X_Class_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) ); if( i !== -1 ) return X_Class_DEF_LIST[ i ]; - i = X_Class_PRIVATE_CLASS_LIST.indexOf( KlassOrInstance ); - if( i === -1 ) i = X_Class_PRIVATE_CLASS_LIST.indexOf( X_Class_getClass( KlassOrInstance ) ); - if( i !== -1 ) return X_Class_PRIVATE_DEF_LIST[ i ]; - if( X_Class_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance; - if( X_Class_PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance; -}; - -function X_Class_newPrivate( /* instance, args */ ){ - var args = X_Object_cloneArray( arguments ), - user = args.shift(), - def = X_Class_getClassDef( user ), - privateClass = def.privateClass, - privateDef = X_Class_getClassDef( privateClass ), - i = -1; - if( def.userList ){ - i = def.userList.indexOf( user ); - } else { - def.userList = []; - def.dataList = []; - }; - if( i !== -1 ){ - X.Logger.critical( 'PrivateData already exist!' ); - return; - }; - if( privateDef._tempUser ){ - X.Logger.critical( 'newPrivate を連続呼び出しされたところ破綻' ); - return; - }; - privateDef._tempUser = user; - return X_Class_actualConstructor( privateClass( X_Closure_COMMAND_BACK ), args );// privateClass.__new( args ); -}; - -function X_Class_getPrivate( instance ){ - var def = X_Class_getClassDef( instance ), - i = def.userList.indexOf( instance ); - if( i !== -1 ) return def.dataList[ i ]; }; /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */ function X_Class_override( target, src, force ){ var p; for( p in src ){ - if( p === 'Super' || p === 'SuperConstructor' || p === '__proto__' || p === 'prototype' || p === 'constructor' ){ - X.Logger.critical( 'Super & SuperConstructor is reserved!' ); + if( p === 'Constructor' ) continue; + if( p === '__proto__' || p === 'prototype' || p === 'constructor' ){ + X.Logger.critical( p + ' is reserved!' ); return; }; - if( force || target[ p ] === void 0 ){ + if( force || target[ p ] === undefined ){ target[ p ] = src[ p ]; }; }; return target; }; +/** + * スーパークラスか?調べます。 + * @alias __ClassBase__.superClassOf + * @param klass {__ClassBase__} + * @return {boolean} + */ function X_Class_superClassOf( klass ){ var myDef = X_Class_getClassDef( this ), targetDef = X_Class_getClassDef( klass ), @@ -343,13 +445,26 @@ function X_Class_superClassOf( klass ){ return false; }; +/** + * サブクラスか?調べます。 + * @alias __ClassBase__.subClassOf + * @type {Function} + * @param klass {__ClassBase__} + * @return {boolean} + */ function X_Class_subClassOf( klass ){ - return X_Class_superClassOf.call( klass, this ); + return klass && X_Class_superClassOf.call( klass, this ); }; - -/* サブクラスを作るメソッド - * var subClass = superClass.inherits( ... ) - * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002 + +/** + * サブクラスを作ります。与える引数は X_Class.create と同じです。http://d.hatena.ne.jp/m-hiyama/20051018/1129605002 + * @alias __ClassBase__.inherits + * @example var SubClass = SuperClass.inherits( 'Sub', X_Class.FINAL, { ... } ); + * @param {string} [displayName] クラスの名前 + * @param {number} [classSetting=0] X_Class.POOL_OBJECT | X_Class.FINAL など + * @param {__ClassBase__=} [privateClass] このクラスとペアで動作するシャドウクラス + * @param {object} [props={}] このクラスのメンバと関数。コンストラクタは Constructor と書くこと + * @return {__ClassBase__} */ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){ var args = X_Object_cloneArray( arguments ), @@ -358,12 +473,12 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props superDef = X_Class_getClassDef( Super ), displayName = args[ 0 ], classSetting, - opt_super, + //opt_super, klass, def; if( superDef.Final ) X.Logger.critical( 'X.Class inherits, Class is final!' ); // サブクラス名 - if( X.Type.isString( displayName ) ){ + if( X_Type_isString( displayName ) ){ args.shift(); } else { displayName = 'SubClass of ' + superDef.displayName; @@ -372,24 +487,22 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props // サブクラス設定 classSetting = args[ 0 ]; - if( X.Type.isNumber( classSetting ) ){ + if( X_Type_isNumber( classSetting ) ){ args.shift(); } else { // クラス設定がない場合、親からコピーして、Abstract flag は落とす?? - classSetting = superDef.setting;// &= ~X.Class.ABSTRACT; + classSetting = superDef.setting;// &= ~X_Class.ABSTRACT; }; - if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA; - opt_super = !!( classSetting & X.Class.SUPER_ACCESS ); + params.push( classSetting ); // サブクラスのシャドウ if( args[ 0 ] && X_Class_getClass( args[ 0 ] ) ){ params.push( args.shift() ); - } else - if( superDef.privateClass ){ - params.push( superDef.privateClass ); }; - params.push( args[ 0 ] ); /* props サブクラスでは未定義でも可 */ + + /* props 未定義でも可 */ + params.push( args[ 0 ] ); // 継承クラスの作成 if( X_Class_useObjectCreate ){ @@ -398,23 +511,16 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props if( X_Class_use_proto_ ){ X_Class_traits = Super.prototype; } else { - //Super.__new = null; X_Class_traits = new Super( X_Closure_COMMAND_DROP ); - //Super.__new = X_Class_actualConstructor; }; - klass = X.Class.create.apply( X.Class, params ); + klass = X_Class_create.apply( X.Class, params ); X_Class_traits = null; def = X_Class_getClassDef( klass ); // 継承用プロパティを控える - if( opt_super === true ){ - def.superAccess = true; - def.SuperClass = Super; - def.SuperProto = Super.prototype; - def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor; - } else { - def.SuperClass = Super; // instanceOf() で親クラスを調べる! - }; + def.SuperClass = Super; + def.SuperProto = Super.prototype; + def.SuperConstructor = superDef.Constructor || superDef.SuperConstructor; return klass; }; @@ -423,85 +529,34 @@ function X_Class_inherits( /* displayName, classSetting, opt_PrivateClass, props * new の実体.コンストラクタの機能は instance.Constructor に書く. * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる */ -function X_Class_actualConstructor( obj, args ){ - var klass = obj.c,//this, - def = X_Class_getClassDef( klass ), - dataUser = def._tempUser, - instance, obj, - userDef; +function X_Class_actualConstructor( f, args ){ + var klass = f.klass, + def = f.classDef, + instance, obj; + if( def.Abstract ){ X.Logger.critical( 'AbstractClass!' ); return; }; - if( def.isPrivate && !dataUser ){ - X.Logger.critical( 'use myClass.newPrivate( instance, ...args )!' ); - return; - }; - //klass.__new = null; - instance = def.pool && def.pool.length > 0 ? + + instance = def.pool && def.pool.length ? def.pool.pop() : X_Class_useObjectCreate ? Object.create( klass.prototype ) : new klass( X_Closure_COMMAND_DROP ); - //klass.__new = X_Class_actualConstructor; - if( def.isPrivate ){ - userDef = X_Class_getClassDef( dataUser ); - userDef.dataList.push( instance ); - userDef.userList.push( dataUser ); - instance.User = dataUser; - def._tempUser = null; - } else { - def.live && def.live.push( instance ); - }; - if( def.superAccess ){ - // TODO klass.prototype に移動 - instance.Super = def.SuperProto; - instance.SuperConstructor = X_Class_superConstructor; - }; + def.live && def.live.push( instance ); + obj = def.Constructor ? def.Constructor.apply( instance, args ) : def.SuperConstructor && def.SuperConstructor.apply( instance, args ); - if( ( X.Type.isObject( obj ) && obj !== instance ) || X.Type.isFunction( obj ) ){ // Class - instance.kill(); + + if( obj !== instance && ( X_Type_isObject( obj ) || X_Type_isFunction( obj ) ) ){ // Class + instance[ 'kill' ](); return obj; }; return instance; }; -/* クラス定義を辿ってスーパークラスのコンストラクタを探す。 - * 呼び出したコンストラクタは配列に控える。 - * さらに呼ばれた場合、配列を元にさらに奥のコンストラクタを取得 - * TODO 現在 new しているインスタンスを保持してチェックする - */ -function X_Class_superConstructor(){ - var sClass = this, - i = X_Class_CALLING_SUPER.indexOf( sClass ), - n = -1, - l, sList, def, sConst, ret; - - if( i === -1 ){ - X_Class_CALLING_SUPER[ l = X_Class_CALLING_SUPER.length ] = sClass; - X_Class_CALL_SUPER_STACK[ l ] = sList = []; - } else { - sList = X_Class_CALL_SUPER_STACK[ i ]; - }; - - while( sClass ){ - def = X_Class_getClassDef( sClass ); - sClass = def.SuperClass; - sConst = def.SuperConstructor; - if( sConst && sList[ ++n ] !== sConst ){ - sList[ n ] = sConst; - ret = sConst.apply( this, arguments ); - --sList.length; - if( !sList.length ){ - X_Class_CALLING_SUPER.splice( i, 1 ); - X_Class_CALL_SUPER_STACK.splice( i, 1 ); - }; - return ret; - }; - }; -}; console.log( 'X.Core.Class' );