1 2 /* 3 4 ******** class template ******** 5 6 用 7 =function(){}() 8 似乎亦可,見 SWFObject 2.2 9 */ 10 11 var ClassT={}; // class template set 讓 addCode 也可以讀通 12 13 14 15 // =================================================== 16 /* 17 ** class description: class template (simple version) 18 19 _=this 20 21 TODO: 22 23 24 HISTORY: 25 2008/7/21 16:12:32 create 26 */ 27 var 28 classT= 29 30 (ClassT.classT=function(initF){ 31 32 var 33 34 // class private ----------------------------------- 35 36 37 // instance constructor --------------------------- 38 instanceL=[], 39 initI=function(a){ 40 var _t=this,_p=pv(_t); 41 instanceL.push(_t); // for destructor 42 //_p.vars=a 43 44 // initial instance object 45 },_=function(){initI.apply(this,arguments);initF&&initF.apply(this,arguments);}, 46 47 48 // (instance private handle) 不要 instance private 的把這函數刪掉即可。 49 _p='_'+(''+Math.random()).replace(/\./,''), 50 // get private variables (instance[,destroy]), init private variables (instance[,access function list[, instance destructor]]) 51 pv=function(i,d,k){var V,K=_p('k');return arguments.callee.caller===_p('i')?(V=_p(i[K]=_p()),V.O=i,V.L={}):(K in i)&&(V=_p(i[K]))&&i===V.O?d?(_p(i[K],1),delete i[K]):V.L:{};}; 52 53 // class destructor --------------------------- 54 /* 55 please call at last (e.g., window.unload) 56 57 usage: 58 classT=classT.destroy(); 59 or if you has something more to do: 60 classT.destroy()&&classT=null; 61 */ 62 63 _.destroy=function(){for(var i=0,l=instanceL.length;i<l;i++)instanceL[i].destroy();_p();}; 64 65 // (instance private handle, continue) 66 eval('_p=(function(){var '+_p+'={a:pv,d:_.destroy,c:0,k:"+pv+'+Math.random()+'",i:initI};return function(i,d){var f=arguments.callee.caller;if(f==='+_p+'.a){if(!d)return i in '+_p+'?'+_p+'[i]:('+_p+'[i='+_p+'.c++]={},i);'+_p+'[i]={};}if(f==='+_p+'.d)'+_p+'={};}})();'); 67 _p.toString=function(){return'';}; 68 69 70 // class public interface --------------------------- 71 72 // func 73 _.func=function(){ 74 var _t=this; 75 76 }; 77 78 // class constructor --------------------------- 79 80 // do something others 81 82 83 _.prototype={ 84 // 應該盡量把東西放在 class,instance 少一點…? 85 // ** important ** 這邊不能作 object 之 initialization,否則因為 object 只會 copy reference,因此 new 時東西會一樣。initialization 得在 _() 中作! 86 87 // instance public interface ------------------- 88 89 setV:function(a){ 90 var _t=this,_p=pv(_t); 91 //_p.vars=a 92 }, 93 94 95 // instance destructor --------------------------- 96 /* 97 usage: 98 instance=instance.destroy(); 99 or if you has something more to do: 100 instance.destroy()&&instance=null; 101 */ 102 destroy:function(){pv(this,1);} 103 }; // _.prototype= 104 105 return _; 106 })(); // function(initF){ 107 108 // =================================================== 109 110 111 112 113 114 115 // 解析 116 117 118 119 // =================================================== 120 121 /* 122 ** class description: class template 123 124 _=this 125 126 TODO: 127 .constructor 設定 128 inherits: 129 http://www.cnblogs.com/birdshome/archive/2005/01/28/95933.html 130 http://www.blogjava.net/zkjbeyond/archive/2006/05/08/45108.html 131 132 133 HISTORY: 134 2008/7/21 16:12:32 create 135 7/24 15:14:16 enhanced by set .toString. But.. If we use delete _p.toString, than we still can.. 136 eval('a = pv',some_instance); 137 eval('var s=_p.toString;delete _p.toString;sl("** test1 _p: "+_p);_p.toString=s;sl("** test2 _p: "+_p);',a); 138 7/26 11:38:6 className 139 140 TOTRY: 141 直接對 eval 下手,使 delete 掉 eval 則 lost data 142 */ 143 var 144 classT_debug= 145 146 // 若是不須讓 addCode 也可以讀通,不加 ClassT.~ 也沒關係。 147 (ClassT.classT=function(initF){ // initF: additional initialization function 148 149 var 150 151 // class private ----------------------------------- 152 className='',//classT 153 154 // variables 155 vars=7, 156 // function 157 doLog=function(m){ 158 var _t=_; 159 sl((className?className+': ':'>> ')+m); // this+': ' 160 }, 161 162 163 164 // instance constructor --------------------------- 165 instanceL=[], // 實例 list 166 initI=function(a){ 167 var _t=this,// 這裡面有用的是 this,不是 arguments.callee。 168 _p=pv(_t);//pv(_t,[func1,func2,..],_.destroy); // init private variables 169 instanceL.push(_t); // for destructor 170 171 // initial instance object 172 _t.property1=[]; 173 174 _t.testV=a; 175 doLog('class create: '+a); 176 177 //return this; 178 }, 179 180 // 盡量減少 instance 體積…有用嗎? 181 _=function(){ 182 initI.apply(this,arguments); 183 initF&&initF.apply(this,arguments); 184 }, 185 186 187 // (instance private handle) 不要 instance private 的把這函數刪掉即可。 188 /* 189 更完整的防治:比對 arguments.callee.caller 的程式碼,確定登錄過才給予存取。 190 …在 eval() 的第二 argument 下無用武之地。 191 */ 192 193 _p='_'+(''+Math.random()).replace(/\./,''), 194 195 pv=function(i,d,k){ // get private variables (instance[,destroy]), init private variables (instance[,access function list[, instance destructor]]) 196 var V,K=_p('k'); 197 /* V: get variables 198 199 V.L variables {} 200 V.O instance 201 202 for full version: 203 V.F 可存取函數的程式碼 list {} 204 V.D instance destructor 205 */ 206 207 // simple version 208 if(0)return arguments.callee.caller===_p('i')? 209 (V=_p(i[K]=_p()),V.O=i,V.L={}) 210 :(K in i)&&(V=_p(i[K]))&&i===V.O? 211 d?(_p(i[K],1),delete i[K]):V.L 212 :{}; // 竄改就會出 trouble 213 214 215 // full version 216 var c=arguments.callee.caller,j=0,l; 217 doLog('pv: '+(c===_p('i')?'init':d?'destory':'get variables')+' by '+c); 218 if(c===_p('i')){ 219 V=_p(i[K]=_p()); 220 V.O=i; 221 if(k)V.D=k; // instance destructor 222 // 登錄可存取函數的程式碼。更狠的:不用 {} 而用 d,確定是 *完全相同* 的 function。 223 if(d instanceof Array) // []: no access!! 224 for(k=V.F={},l=d.length;j<l;j++) 225 k[d[j]]=1; 226 return V.L={}; 227 } 228 229 // 預防竄改,找尋本來應該的 index。 230 if(!(K in i)||!(V=_p(i[K]))||i!==V.O) 231 for(k=_p('c');j<k;j++) 232 if(i===_p(j).O){ 233 doLog('pv: correct index: '+i[K]+' to '+j); 234 i[K]=j; 235 break; 236 } 237 238 if((K in i)&&(V=_p(i[K]))&&i===V.O) 239 if(d){ 240 // call from instance destructor 241 if(!V.D||c===V.D)_p(i[K],1),delete i[K]; 242 //else throw new Error(3,'Error calling to destroy.'); 243 }else if(!V.F||V.F[c]){ 244 doLog('pv: get index '+i[K]+'.'); 245 //if(!V.L)throw new Error(1,'Error to get variables! Maybe it was already destroyed?');//private variables 246 return V.L; 247 } 248 249 return {}; // throw new Error(1,'Illegal access!'); 250 }; // of pv=function( 251 252 253 // (for inherits) 254 /* 255 不要 inherit 的把這段刪掉即可。 256 usage: 257 // 模擬 inherits 258 newClass=oldClass.clone(); 259 // prevent re-use. 防止再造 260 delete oldClass.clone; 261 */ 262 (_.clone=arguments.callee).toString=function(){return '[class_template]';}; 263 264 265 // class destructor --------------------------- 266 /* 267 please call at last (e.g., window.unload) 268 269 usage: 270 classT=classT.destroy(); 271 or if you has something more to do: 272 classT.destroy()&&classT=null; 273 */ 274 275 _.destroy=function(){ 276 doLog('destroy: Destroy class.'); 277 for(var i=0,l=instanceL.length;i<l;i++) 278 instanceL[i].destroy(); 279 _p(); 280 }; 281 282 283 // class public interface --------------------------- 284 285 // variables 286 _.variables={}; 287 // func 288 _.func=function(){ 289 var _t=this; 290 291 }; 292 293 294 // (instance private handle, continue) 295 // .a: accessable caller function, .d: class destructor, c:count, .k: private variables keyword, .i: init function, m: accessable class members 296 // destructor: (index,1) Warning: 某些環境中 Array 可能無法用 delete? 297 eval('_p=(function(){var '+_p+'={a:pv,d:_.destroy,c:0,k:"+pv+'+Math.random()+'",i:initI,m:{_:{}}}; (function(m,i){for(i=0;i<m.length;i++)if(m[i])'+_p+'.m[m[i]]=1;})([' 298 //'func1,func2' // 在這裡填上需要 call 隱藏數值的 class private function。若無,可考慮合併到 _.destroy 前。 299 +']); return function(i,d){var f=arguments.callee.caller;if(f==='+_p+'.a){if(!d)return i in '+_p+'?'+_p+'[i]:('+_p+'[i='+_p+'.c++]={},i);'+_p+'[i]={};}if('+_p+'.m[f])return '+_p+'.m._;if(f==='+_p+'.d)'+_p+'={};}})();'); 300 _p.toString=function(){return '';}; 301 302 303 // class constructor --------------------------- 304 305 // do something others 306 307 308 _.prototype={ 309 // 應該盡量把東西放在 class,instance 少一點…? 310 311 // instance public interface ------------------- 312 313 // ** important ** 這邊不能作 object 之 initialization,否則因為 object 只會 copy reference,因此 new 時東西會一樣。initialization 得在 _() 中作! 314 property1:[], 315 316 setV:function(m){ 317 var _t=this,_p=pv(_t); 318 doLog('setV: class vars='+(vars=m)+', this.vars='+(_p.vars=m)); 319 }, 320 321 getV:function(){ 322 var _t=this,_p=pv(_t); 323 doLog('getV: class vars='+vars+', this.vars='+_p.vars); 324 }, 325 326 327 // instance destructor --------------------------- 328 329 /* 330 usage: 331 instance=instance.destroy(); 332 or if you has something more to do: 333 instance.destroy()&&instance=null; 334 335 TODO: Need *auto* detect if the object is destroyed. 336 */ 337 destroy:function(){ 338 // If you need to do something (e.g, destroy sub-sub-objects) before destroy it, you need to call pv(this) first here. 339 pv(this,1); 340 } 341 342 }; // _.prototype= 343 344 // class name --------------------------- 345 if(className){ 346 _.prototype.toString=_.toString=function(){return '[class '+className+']';};//classT 347 //eval('var className=_',this); // 行不通 348 } 349 350 return _; 351 })(); // (function(){ 352 353 354 // =================================================== 355 356 357 /* 358 // test suit 359 sl('<hr/>'); 360 var c1=new classT(123),c2=new classT(456); 361 362 c1.setV('Hello'); 363 c2.setV('World'); 364 c1.getV(); 365 c2.getV(); 366 367 sl(c1.testV+','+c2.testV); 368 369 c1.destroy(); 370 c2.destroy(); 371 classT.destroy(); 372 */ 373 374 375 376 377 378 /* 379 繼承 380 http://www.cnblogs.com/birdshome/archive/2005/01/28/95933.html 381 382 383 引入arguments.length:這代表傳入引數個數(長度),arguments.callee.length:這代表(function)自身定義的引數個數(長度) 384 function fn(){ 385 var _f=arguments.callee; // f: function, flag 引入arguments.callee:這代表(function)自身 386 // 以 _f.* 替代 fn.* 387 alert('fn: _f.val='+_f.val); 388 } 389 fn.subfn=function(){ 390 var _f=arguments.callee; // function, flag 391 // 當不用 new 時,以 _f.* 替代 fn.subfn.*,this.* 替代 fn.*。但在 (fn.subfn=function(){ .. }) 中間就不能用 this, _f 392 alert('fn.subfn: this.val='+this.val); // *** !!WARNING!! 在 eval() 中 this 可能表示 window,這時就無法用 this 來得到 fn 了。 393 alert('fn.subfn: _f.val='+_f.val); 394 }; 395 fn.subfn.val='test value: fn.subfn.val'; 396 fn.val='test value: fn.val'; 397 fn.prototype={ 398 constructor:fn, // need to adjust 399 subfn:function(){ 400 var _f=arguments.callee; // function, flag 401 // 當不用 new 時,以 _f.* 替代 fn.subfn.*,this.* 替代 fn.* 402 alert('fn.prototype.subfn: this.val='+this.val); 403 alert('fn.prototype.subfn: _f.val='+_f.val); 404 alert('fn.prototype.subfn: this.constructor.val='+this.constructor.val); 405 }, 406 val:'test value: fn.prototype.val' 407 }; // fn.prototype={ 408 fn.prototype.subfn.val='test value: fn.prototype.subfn.val'; 409 var inst=new fn; 410 //inst.constructor.subfn(); 411 inst.subfn(); 412 413 414 var obj={ 415 val:34, 416 fn:function(){ 417 var _f=arguments.callee; // function, flag 418 // 以 _f.* 替代 obj.subfn.*,this.* 替代 obj.* 419 alert(this.val); 420 } 421 }; 422 ww.ee(); 423 424 425 426 to hack @ Firefox 3.0: https://bugzilla.mozilla.org/show_bug.cgi?id=442333 427 假設 scope obj.fn 裡有一個 foo 變數,在 Firefox 上可以使用 var a; eval('a = foo', obj.fn) 把 foo 變數抓到 a 裡面,所以你如果有使用這種方法來放與安全性有關的東西,就得重新檢查一次程式碼:Module Pattern Provides No Privacy…at least not in JavaScript(TM)。在一陣討論後,這個功能打算在 Firefox 3.1 拿掉:Remove eval's optional second argument。 428 429 */ 430 431 432 /* 433 實作class: 434 http://www.remus.dti.ne.jp/~a-satomi/bunsyorou/ArekorePopup.html 435 http://www.klstudio.com/post/32.html 436 function classA(){ 437 // define property 438 // array 439 this.attrs=['title','href','cite','datetime']; 440 // object 441 this.ns={ 442 xhtml1:'http://www.w3.org/1999/xhtml', 443 xhtml2:'http://www.w3.org/2002/06/xhtml2', 444 }; 445 return this; 446 } 447 classA.prototype={ 448 // function 449 launch:function(){}, 450 init:function(){}, 451 // object 452 scanNode:{ 453 recursive:function(node){} 454 }, 455 // http://dean.edwards.name/weblog/2005/10/add-event/ 456 addEvent:function(obj,type,listener){ 457 if (obj.addEventListener) // Std DOM Events 458 obj.addEventListener(type, listener, false); 459 else if (obj.attachEvent) // IE 460 obj.attachEvent( 461 'on' + type, 462 function() { listener( { 463 type : window.event.type, 464 target : window.event.srcElement, 465 currentTarget : obj, 466 clientX : window.event.clientX, 467 clientY : window.event.clientY, 468 pageY : document.body.scrollTop + window.event.clientY, 469 keyCode : window.event?window.event.keyCode:e?e.which:0, 470 shiftKey : window.event.shiftKey, 471 stopPropagation : function() { window.event.cancelBubble=true; } 472 } ) } 473 ); 474 } 475 }; 476 var A=new classA(); 477 478 479 */ 480 481 482