|
我們來模仿一下最OO的mootools的繼承機制。它的類都有一個叫做initialize構(gòu)造方法,這與Java的類都有一個與類名同名的構(gòu)造方法一樣的道理。只不過,這些叫initialize或init都是借鑒自Prototype,而Prototype那幫人是Ruby出身。為了區(qū)別mootools那種污染原生方法的做法,我把類的構(gòu)造器命名為variant,并且禁止查看構(gòu)造方法(像瀏覽器禁止查看原生對象的構(gòu)造方法那樣)。
var variant = function (options){ options = options || {}; var initialize = options.initialize || function(){}; var klass = initialize ; klass.constructor = arguments.callee; klass.prototype.constructor = klass; klass.toString = function(){//禁止查看構(gòu)造方法 return "function variant(){/n [variant code]/n}" } return klass; };
這是一個非常簡單的工廠方法,用于生產(chǎn)類的。options就是一屬性包,可能裝有我們的類的構(gòu)造方法,我們要做的是把它提取出來,然后輸送出去。
function factory(a){ a.b = b; a.c = c; return a; }
不過,這就有點像倒?fàn)敚覀儜?yīng)該像水果商,從果農(nóng)收購水果回來包裝一番,才賣出去。這包裝就是往要生成的類添加各種原型方法與類方法。我們進一步打造我們的類工廠,讓生產(chǎn)的類擁有繼承能力,也就是把第一部分的makeBridge 加上去。
prototype繼承是通過把子類的原型設(shè)置成父類的一個實例來進行繼承的。因此無論是inherit也好,mixin也好,都是往子類的原型添加?xùn)|西。打個比方,繼承就是把一大堆屬性與方法直接加在子類的原型上,mixin則相當(dāng)于把一打?qū)傩耘c方法逐一加到構(gòu)造函數(shù)的原型。不過在上面Tiger類的構(gòu)造器寫得有點不好,因為name屬性本來父類就有,子類就不用定義一次。如果父類有許多實例屬性,豈不是要寫一大打賦值語句。應(yīng)該改為
var Tiger = variant({ inherit:Animal, initialize:function(name,age){ this.superclass(arguments);//this.name = name this.age =age; }, getAge : function(){ return this.age; }, setAge : function(age){ this.age = age; } })
但是這種做法在第三代子類就行不通了,比如我們弄個子類叫IndiaTiger,它比Tiger多出一個類例屬性location。
var IndiaTiger = variant({ inherit:Tiger, initialize:function(name,age,location){ this.superclass(arguments); this.location =location; } });
當(dāng)new印度虎實例時就報錯了,除非其父類的構(gòu)造器沒有用到this.superclass(arguments)。不用說,問題是出自this,它的不確定性總是為我們?nèi)呛芏嗦闊_@里的this總為IndiaTiger 的實例,因此this.superclass總為Tiger ,也因此我們無法實例化Animal 。Javascript的實例化過程是,有父類先實例化父類,然后再到下級子類。由于我們無法通過klass.prototype.superclass獲取Animal,我們可以用klass.superclass來試一下。klass為類,而this為實例:
IndiaTiger.superclass.apply(this, arguments);//this為IndiaTiger 的實例//arguments為IndiaTiger 構(gòu)造器的參數(shù)對象
但我們不能把前面的IndiaTiger 寫死,因為創(chuàng)建IndiaTiger 這個類時,它還不知自己叫IndiaTiger ,我們可以通過arguments.callee獲取IndiaTiger自身。Tiger的構(gòu)造相仿。
var IndiaTiger = variant({ inherit:Tiger, initialize:function(name,age,location){ arguments.callee.superclass.apply(this, arguments); this.location =location; } });
我們可以把它再抽取出來,這樣每次就不用寫這么長的代碼了。
function _super(o, args) {//o為子類的實例,agrs為子類構(gòu)造的arguments對象 return args.callee.superclass.apply(o, args); }
上面的代碼已經(jīng)假設(shè)了,它的構(gòu)造器總會有inherit這個屬性,但如果沒有豈不是會報錯,另,它還假設(shè)了我們的類上面有一個屬性叫superclass,因此我們要在類工廠中做相應(yīng)的調(diào)整。添加或修改如下兩行代碼:
var superclass = options.inherit || Object; klass.superclass = superclass; //類的superclass
不過每次設(shè)置新類的構(gòu)造器時都要添加一行_super(this,arguments)也太麻煩了,最好把它隱藏起來,內(nèi)部調(diào)用。另,把_super方法放到工廠外,顯得太松散,既然也是用來構(gòu)建類,因此也該把它整合到類工廠中。
function factory(a){ var b = function(){ s(); a(); //*****其他方法 } return b }
也就是說,我們只要這樣設(shè)置類的構(gòu)造器即可:
var IndiaTiger = Variant({ inherit:Tiger, initialize:function(name,age,location){ this.location =location;//★★★★★ } });
it知識庫:javascript框架之繼承機制(二),轉(zhuǎn)載需保留來源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請第一時間聯(lián)系我們修改或刪除,多謝。