dojo分析之declare接口

歡迎轉載opendevkit文章, 文章原始地址: http://www.opendevkit.com/?e=57

declare接口是dojo定義類系統的關鍵函數, 類系統就是抽象,封裝,繼承.dojo用javascript的prototype實現繼承, 用mixin實現派生, javascript一切都是函數, 這自己就是高度抽象.巧妙的地方在於: 對於一個類, 有構造函數和類名字, 實際上構造函數是用戶自定義的函數, 類名字也是用戶自定的, 怎麼實現用戶使用new操做符的時候, 構造整個對象呢?javascript

1. 對象從哪來

好比, Dialog.js裏聲明瞭一個dijit.Dialog, 這是一個var,仍是一個函數?實際上, 在declare接口裏:java

 817         // add name if specified
 818         if(className){
 819             proto.declaredClass = className;                                                                                               
 820             lang.setObject(className, ctor);
 821         }
紅 字部分, 把dijit.Dialog聲明成了一個對象, 而且賦值爲ctor, 實際上ctor是一個函數, 立刻就說會說到. 當new操做的時候, 實際上調用的是ctor這個函數, 這個函數並非dijit.Dialog裏constructor(繼承_Widget.js).app

2. 關聯類名字的函數ctor

declare接口裏:函數

 768                 // chain in new constructor                                                                                                
 769                 ctor = new Function;
 770                 ctor.superclass = superclass;
 771                 ctor.prototype = proto;
 772                 superclass = proto.constructor = ctor;
ctor首先是一個匿名函數, 接下來的post

 799         bases[0] = ctor = (chains && chains.constructor === "manual") ? simpleConstructor(bases) :
 800             (bases.length == 1 ? singleConstructor(props.constructor, t) : chainedConstructor(bases, t));
實際上給ctor賦值了simpleConstructor或者chainedConstructor的返回值, 而好比this

simpleConstructor的返回值是個函數:spa

 441     // plain vanilla constructor (can use inherited() to call its base constructor)
 442     function simpleConstructor(bases){
 443         return function(){
 444             var a = arguments, i = 0, f, m;
 445
 446             if(!(this instanceof a.callee)){
 447                 // not called via new, so force it
 448                 return applyNew(a);
 449             }
 450
 451             //this._inherited = {};
 452             // perform the shaman's rituals of the original declare()
 453             // 1) do not call the preamble
 454             // 2) call the top constructor (it can use this.inherited())
 455             for(; f = bases[i]; ++i){ // intentional assignment
 456                 m = f._meta;
 457                 f = m ? m.ctor : f;
 458                 if(f){
 459                     f.apply(this, a);
 460                     break;
 461                 }
 462             }
 463             // 3) call the postscript
 464             f = this.postscript;
 465             if(f){
 466                 f.apply(this, a);
 467             }
 468         };
 469     }
也就是ctor =  441     // plain vanilla constructor (can use inherited() to call its base constructor)
 442     function simpleConstructor(bases){
 443         return function(){
 444             var a = arguments, i = 0, f, m;
 445
 446             if(!(this instanceof a.callee)){
 447                 // not called via new, so force it
 448                 return applyNew(a);
 449             }
 450
 451             //this._inherited = {};
 452             // perform the shaman's rituals of the original declare()
 453             // 1) do not call the preamble
 454             // 2) call the top constructor (it can use this.inherited())
 455             for(; f = bases[i]; ++i){ // intentional assignment
 456                 m = f._meta;
 457                 f = m ? m.ctor : f;
 458                 if(f){
 459                     f.apply(this, a);
 460                     break;
 461                 }
 462             }
 463             // 3) call the postscript
 464             f = this.postscript;
 465             if(f){
 466                 f.apply(this, a);
 467             }
 468         };
 469     }
也就是ctor是一個函數, 函數體裏 :prototype

 455             for(; f = bases[i]; ++i){ // intentional assignment
 456                 m = f._meta;
 457                 f = m ? m.ctor : f;
 458                 if(f){
 459                     f.apply(this, a);
 460                     break;orm

也就是當new調用這個對應dijit.Dialog的ctor的時候, 會執行_meta.ctor, 實際就是聲明裏邊的constructor, 以後又調用:對象

 463             // 3) call the postscript
 464             f = this.postscript;
 465             if(f){
 466                 f.apply(this, a);
 467             }

3. 總結

declare接口, 聲明一個類, 實際上就是定一個了一個xxxx.xxxx.xxx這樣的名字的一個函數, 名字就是類名, 函數就是調用constructor和postscript兩個回調的ctor.

當, new的時候, xxx.xxx.xxx被調用, 近而調用了constructor和postscript函數.

須要理解具體的構造過程的話, 須要關注 : simpleConstructor和chainedConstructor.
相關文章
相關標籤/搜索