2 * Class を定義し システムの管理下に置く.
\r
3 * 全てのクラスと pool が有効の場合インスタンスへの参照が保持される.
\r
4 * 1. X.Class.create( def, opt_final, opt_pool, opt_abstract ) でクラスを登録.
\r
5 * 2. コンストラクタ となるメソッドは、Constructor : function( arg ){ ... }, に書く.
\r
6 * 3. 通常通り new で インスタンス生成
\r
7 * 4. kill() でオブジェクトをクリーンして削除、pool が有効の場合は pool される.
\r
8 * 5. pool が有効の場合、new で pool されたインスタンスが返される.
\r
12 X.Class = ( function(){
\r
13 var CLASS_LIST = [],
\r
15 PRIVATE_CLASS_LIST = [],
\r
16 PRIVATE_DEF_LIST = [],
\r
17 CONSTRUCTOR = 'Constructor',
\r
18 killPrivateFlag = false,
\r
20 useObjectCreate = false, // !!Object.create, http://jsperf.com/prototype-vs-object-create-perf
\r
21 use__proto__ = !!X.emptyFunction.prototype.__proto__;
\r
22 _DEF_LIST = DEF_LIST;
\r
24 * var subClass = superClass.inherits( ... )
\r
25 * http://d.hatena.ne.jp/m-hiyama/20051018/1129605002
\r
27 function inherits( /* displayName, classSetting, opt_PrivateClass, props */ ){
\r
28 var args = X.copyArray( arguments ),
\r
31 superDef = X.Class._getClassDef( Super ),
\r
32 displayName = args[ 0 ],
\r
36 if( superDef.Final ) X.Notification.critical( 'X.Class inherits, Class is final!' );
\r
39 if( X.Type.isString( displayName ) ){
\r
42 displayName = 'SubClass of ' + superDef.displayName;
\r
44 params.push( displayName );
\r
47 classSetting = args[ 0 ];
\r
48 if( X.Type.isNumber( classSetting ) ){
\r
51 // クラス設定がない場合、親からコピーして、Abstract flag は落とす??
\r
52 classSetting = superDef.setting;// &= ~X.Class.ABSTRACT;
\r
54 if( superDef.isPrivate ) classSetting = classSetting | X.Class.PRIVATE_DATA;
\r
55 opt_super = !!( classSetting & X.Class.SUPER_ACCESS );
\r
56 params.push( classSetting );
\r
59 if( args[ 0 ] && X.Class._getClass( args[ 0 ] ) ){
\r
60 params.push( args.shift() );
\r
62 if( superDef.privateClass ){
\r
63 params.push( superDef.privateClass );
\r
65 params.push( args[ 0 ] ); /* props サブクラスでは未定義でも可 */
\r
68 if( useObjectCreate ){
\r
69 traits = Object.create( Super.prototype );
\r
72 traits = Super.prototype;
\r
75 traits = new Super();
\r
78 klass = X.Class.create.apply( X.Class, params );
\r
82 if( opt_super === true ){
\r
83 def = X.Class._getClassDef( klass );
\r
85 def.SuperProto = Super.prototype;
\r
86 def.SuperConstructor = superDef[ CONSTRUCTOR ] || superDef.SuperConstructor;
\r
92 /* X.Class.create で作られたクラスのインスタンスが共通で備えるメソッド
\r
98 var instance = this,
\r
99 klass = X.Class._getClass( instance ),
\r
100 def = X.Class._getClassDef( klass ),
\r
102 if( def.isPrivate === true && killPrivateFlag === false ){
\r
103 X.Notification.critical( 'PrivateInstance.kill() work in PrivateUser.kill().' );
\r
106 killPrivateFlag = false; // onKill 内で PrivateInstance.kill() を防ぐため
\r
107 // onKill() === false の場合、kill のキャンセル
\r
108 // private は false での キャンセル は無視される
\r
109 // TODO kill instance event
\r
110 if( X.Type.isFunction( instance.onKill ) && instance.onKill() === false && !def.isPrivate ){
\r
113 for( p in instance ){
\r
114 if( instance.hasOwnProperty && !instance.hasOwnProperty( p ) ) continue;
\r
115 delete instance[ p ];
\r
118 def.live && def.live.splice( def.live.indexOf( instance ), 1 );
\r
119 def.pool[ def.pool.length ] = instance;
\r
121 if( def.privateClass ){
\r
122 i = def.userList.indexOf( instance );
\r
124 data = X.Class._getPrivate( instance );
\r
125 killPrivateFlag = true;
\r
127 def.dataList.splice( i, 1 );
\r
128 def.userList.splice( i, 1 );
\r
136 instanceOf : function( klass ){
\r
138 if( this.constructor === klass ) return true;
\r
139 while( Super = X.Class._getClassDef( Super ).Super ){
\r
140 if( Super === klass ) return true;
\r
147 * new の実体.コンストラクタの機能は instance.Constructor に書く.
\r
148 * これにより pool された オブジェクト(破棄されたインスタンス) を再利用できる
\r
150 /* Constructor Real for GeneralClass */
\r
151 function C( args ){
\r
153 def = X.Class._getClassDef( klass ),
\r
154 dataUser = def._tempUser,
\r
157 if( def.Abstract === true ){
\r
158 X.Notification.critical( 'AbstractClass!' );
\r
161 if( def.isPrivate === true && dataUser === null ){
\r
162 X.Notification.critical( 'use myClass.newPrivate( instance, ...args )!' );
\r
165 klass.__new = null;
\r
166 instance = def.pool && def.pool.length > 0 ?
\r
169 Object.create( klass.prototype ) :
\r
172 if( def.isPrivate === true ){
\r
173 userDef = X.Class._getClassDef( dataUser );
\r
174 userDef.dataList.push( instance );
\r
175 userDef.userList.push( dataUser );
\r
176 instance.User = dataUser;
\r
177 def._tempUser = null;
\r
179 def.live && def.live.push( instance );
\r
182 // TODO klass.prototype に移動
\r
183 instance.Super = def.SuperProto;
\r
184 instance.SuperConstructor = superConstructor;
\r
186 obj = def[ CONSTRUCTOR ] ?
\r
187 def[ CONSTRUCTOR ].apply( instance, args ) :
\r
188 def.SuperConstructor &&
\r
189 def.SuperConstructor.apply( instance, args );
\r
190 if( X.Type.isObject( obj ) && obj !== instance ){
\r
197 function superConstructor(){
\r
198 var s = X.Class._getClassDef( this ).SuperConstructor;
\r
199 s && s.apply( this, arguments );
\r
208 create : function( /* displayName, classSetting, opt_PrivateClass, props */ ){
\r
209 var args = X.copyArray( arguments ),
\r
210 displayName = args[ 0 ],
\r
212 opt_pool, opt_abstract, opt_final, opt_private,
\r
217 if( X.Type.isString( displayName ) === true ){
\r
218 classDef.displayName = displayName;
\r
223 classDef.setting = classSetting = args[ 0 ];
\r
224 if( X.Type.isNumber( classSetting ) ){
\r
225 opt_pool = !!( classSetting & X.Class.POOL_OBJECT );
\r
226 opt_abstract = !!( classSetting & X.Class.ABSTRACT );
\r
227 opt_final = !!( classSetting & X.Class.FINAL );
\r
228 opt_private = !!( classSetting & X.Class.PRIVATE_DATA );
\r
229 if( opt_final && opt_abstract ){
\r
230 X.Notification.critical( 'final & Abstract!' );
\r
235 classDef.setting = 0;
\r
239 if( PRIVATE_CLASS_LIST.indexOf( args[ 0 ] ) !== -1 ){
\r
240 privateDef = X.Class._getClassDef( args[ 0 ] );
\r
241 if( privateDef.isPrivate !== true ){
\r
242 X.Notification.critical( 'PrivateClass not found! please, X.Class.create( X.Class.PRIVATE, {...} ).' );
\r
245 if( privateDef.Abstract === true ){
\r
246 X.Notification.critical( 'PrivateClass is Abstract!' );
\r
249 classDef.privateClass = args.shift();
\r
254 if( !X.Type.isObject( props ) ){
\r
255 // サブクラスの場合、クラス定義の上書きがなくても作成可能
\r
256 // サブクラスでなくても、クラスメンバ用オブジェクトが無しでも作成可能
\r
258 // X.Notification.critical( 'No Class Def!' );
\r
263 if( props[ CONSTRUCTOR ] && X.Type.isFunction( props[ CONSTRUCTOR ] ) ){
\r
264 classDef[ CONSTRUCTOR ] = props[ CONSTRUCTOR ];
\r
267 klass = new Function( 'var a=arguments,f=a.callee;if(f.__new)return f.__new(a)' );
\r
269 klass.superClassOf = X.Class._superClassOf;
\r
270 klass.subClassOf = X.Class._subClassOf;
\r
272 if( useObjectCreate ){
\r
273 klass.prototype = X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );
\r
274 klass.prototype.constructor = klass;
\r
276 if( use__proto__ ){
\r
277 X.Class._override( klass.prototype, props, true );
\r
279 klass.prototype.__proto__ = traits;
\r
281 X.Class._override( klass.prototype, CommonProps, false );
\r
284 klass.prototype = X.Class._override( X.Class._override( traits || klass.prototype, props, true ), CommonProps, false );
\r
285 klass.prototype.constructor = klass;
\r
287 klass.name = displayName;
\r
289 if( opt_abstract === true ){
\r
290 classDef.Abstract = true;
\r
292 if( opt_pool === true ){
\r
293 classDef.pool = [];
\r
294 if( opt_private === false ) classDef.live = [];
\r
296 if( opt_final === true ){
\r
297 classDef.Final = true;
\r
299 klass.inherits = inherits;
\r
301 if( opt_private === true ){
\r
302 if( classDef.privateClass ){
\r
303 X.Notification.critical( 'Private Data Class has no PrivateClass!' );
\r
306 classDef.isPrivate = true;
\r
307 PRIVATE_CLASS_LIST.push( klass );
\r
308 PRIVATE_DEF_LIST.push( classDef );
\r
310 CLASS_LIST.push( klass );
\r
311 DEF_LIST.push( classDef );
\r
315 sys_shutdown : function(){
\r
318 _getClass : function( instance ){
\r
319 var cList = CLASS_LIST,
\r
323 klass = cList[ --i ];
\r
324 if( instance.constructor === klass ) return klass;
\r
326 cList = PRIVATE_CLASS_LIST;
\r
329 klass = cList[ --i ];
\r
330 if( instance.constructor === klass ) return klass;
\r
333 if( cList.indexOf( instance ) !== -1 ) return instance;
\r
334 if( CLASS_LIST.indexOf( instance ) !== -1 ) return instance;
\r
336 _getClassDef : function( KlassOrInstance ){
\r
337 var i = CLASS_LIST.indexOf( KlassOrInstance );
\r
338 if( i === -1 ) i = CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );
\r
339 if( i !== -1 ) return DEF_LIST[ i ];
\r
341 i = PRIVATE_CLASS_LIST.indexOf( KlassOrInstance );
\r
342 if( i === -1 ) i = PRIVATE_CLASS_LIST.indexOf( X.Class._getClass( KlassOrInstance ) );
\r
343 if( i !== -1 ) return PRIVATE_DEF_LIST[ i ];
\r
345 if( DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;
\r
346 if( PRIVATE_DEF_LIST.indexOf( KlassOrInstance ) !== -1 ) return KlassOrInstance;
\r
348 _newPrivate : function( /* instance, args */ ){
\r
349 var args = X.copyArray( arguments ),
\r
350 user = args.shift(),
\r
351 def = X.Class._getClassDef( user ),
\r
352 privateClass = def.privateClass,
\r
353 privateDef = X.Class._getClassDef( privateClass ),
\r
355 if( def.userList ){
\r
356 i = def.userList.indexOf( user );
\r
362 X.Notification.critical( 'PrivateData already exist!' );
\r
365 if( privateDef._tempUser ){
\r
366 X.Notification.critical( 'newPrivate を連続呼び出しされたところ破綻' );
\r
369 privateDef._tempUser = user;
\r
370 return privateClass.__new( args );
\r
372 _getPrivate : function( instance ){
\r
373 var def = X.Class._getClassDef( instance ),
\r
374 i = def.userList.indexOf( instance );
\r
375 if( i !== -1 ) return def.dataList[ i ];
\r
377 /* over のプロパティを target にコピーする.ただし target の プロパティが優先, force で解除 */
\r
378 _override : function ( target, src, force ){
\r
381 if( p === 'Super' || p === 'SuperConstructor' || p === '__proto__' || p === 'prototype' || p === 'constructor' ){
\r
382 X.Notification.critical( 'Super & SuperConstructor is reserved!' );
\r
385 if( force || target[ p ] === void 0 ){
\r
386 target[ p ] = src[ p ];
\r
391 _superClassOf : function(){
\r
394 _subClassOf : function(){
\r
400 console.log( 'X.Core.Class' );
\r