javascript架構之繼承機制

來源:互聯網
上載者:User

大一點的架構都有這個東西。Prototype原來的繼承機制非常弱,為了與mootools對抗也強化了這一方面。嘛,要用原型繼承來模仿類繼承,都基本存在一個複製函數。把父類的原型屬性複製到子類上去。理念的東西暫時這麼多,動手實踐一下最實際。我們設計一個數組類,擁有原生數組的能力與新擴充的能力。

<br /> var isNumber = function(n){<br /> return typeof n === 'number' && isFinite(n);<br /> }<br /> var vArray = function(){<br /> if(arguments.length == 0){<br /> return [];<br /> }else if(arguments.length == 1 && isNumber(arguments[0])){<br /> return new Array(arguments[0]);<br /> }else if(arguments.length > 1){<br /> return Array.prototype.slice.apply(arguments);<br /> }<br /> }<br /> var a = vArray();<br /> alert(a);<br /> var b = vArray(7);<br /> alert(b);<br /> var c = vArray(1,3,"司徒正美",true);<br /> alert(c);<br />

運行代碼

很顯然這是Factory 方法,產生的原生數組,如果要擴充而不汙染原生數組就又要再加一重封裝。我們看繼承是怎樣實現的。這涉及到兩個類,原生數組類與新數組類。先看代碼:

<br /> var Parent = function(){};<br /> Parent.prototype = Array.prototype;<br /> var Array2 = function(){};<br /> Array2.prototype = new Parent;<br /> Array2.prototype.newMethod = function(){<br /> return "newMethod";<br /> };<br /> Array2.prototype.constructor = Array2;<br /> var a = new Array2("dd",4);<br /> alert(a.newMethod)<br /> var b = new Array("dd",4);<br /> alert(b.newMethod)<br />

運行代碼

由於javascript的原型鏈的關係,我們不能直接var Array2 = Array;var a = new Array2;這樣一旦從Array2的原型添加新方法(添加方法都建議往原型裡加,不建議做成類方法)時,Array的原型也被加上了,因為它們是在同一條船上。我們必須斷開它們。於是我們需要一個Parent函數做橋接。我們可以說Array為目標父類,Parent為真正父類。先把目標父類的原型賦給Parent的原型,這樣Parent就擁有其所有公開的方法,然後我們再把這些方法賦給Array2。但這時Array2的執行個體的constructor 仍為原生的數組,我們要修正一下,也就是把它的原型上的constructor屬性指向自己(Array2)即可(原來是Array)。我們可以參見看Prototype與constructor的關係。

我們再把部分代碼抽取出來做成一個方法:

       var makeBridge = function(klass) {          var bridge = function() {};          bridge.prototype = klass.prototype;          return new bridge;        }        Array2 = function(){};        Array2.prototype = makeBridge(Array);        Array2.prototype.constructor = Array2;

我們再看如何添加新屬性與方法。

<br /> _mixin = function(/*Object*/ obj, /*Object*/ hash){<br /> var nil = {};<br /> //取出dojo,是我看過的所有淺複製方法中最謹慎的<br /> //首先設定一個Null 物件,那麼它的nil[i]方法肯定來自其原型Object.prototype<br /> //確保擴充包hash中的方法或屬性在與Object.prototype的不一樣,<br /> //或者是未定義,才能添加<br /> for(var x in hash){<br /> if(nil[x] === undefined || nil[x] != hash[x]){<br /> obj[x] = hash[x];<br /> }<br /> }<br /> // 在IE不能通過for...in迴圈中添加toString方法<br /> if(!+"\v1" && hash){<br /> var p = hash.toString;<br /> if(typeof p == "function" && p != obj.toString && p != nil.toString &&<br /> p != "\nfunction toString() {\n [native code]\n}\n"){<br /> obj.toString = hash.toString;<br /> }<br /> }<br /> return obj; // Object<br /> };</p><p> var makeBridge = function(klass) {<br /> var bridge = function() {};<br /> bridge.prototype = klass.prototype;<br /> return new bridge;<br /> }<br /> Array2 = function(){};</p><p> Array2.prototype = makeBridge(Array)<br /> _mixin(Array2.prototype,{<br /> newMethod : function(){<br /> return "newMethod"<br /> },<br /> newMethod2 : function(){<br /> return "newMethod2"<br /> },<br /> constructor: Array2<br /> })<br /> var a = new Array2("dd",4);<br /> for(var i in a){<br /> alert(i + " " + a[i])//在IE不能遍曆出constructor屬性<br /> }<br />

運行代碼

上面的_mixin方法是最常見的繼承方法,早期的Prototype也是依靠來拷貝原型方法,堂而皇之地稱之為extend,而且什麼也情況也不考慮。在Ext這裡分成幾種情況apply,applyif,override。在mootools中則叫add。

好了,我們來考慮如何訪問父類方法(我們可以通過重載方法來區分哪是子類方法,哪是父類方法)。要想訪問父類方法,就必須能訪問父類,我們把父類的名稱儲存在子類原型的一個屬性即可。我們把makeBridge方法擴充一下,更名為inherit。

<br /> _mixin = function(/*Object*/ obj, /*Object*/ hash){<br /> var nil = {};<br /> //取出dojo,是我看過的所有淺複製方法中最謹慎的<br /> //首先設定一個Null 物件,那麼它的nil[i]方法肯定來自其原型Object.prototype<br /> //確保擴充包hash中的方法或屬性在與Object.prototype的不一樣,<br /> //或者是未定義,才能添加<br /> for(var x in hash){<br /> if(nil[x] === undefined || nil[x] != hash[x]){<br /> obj[x] = hash[x];<br /> }<br /> }<br /> // 在IE不能通過for...in迴圈中添加toString方法<br /> if(!+"\v1" && hash){<br /> var p = hash.toString;<br /> if(typeof p == "function" && p != obj.toString && p != nil.toString &&<br /> p != "\nfunction toString() {\n [native code]\n}\n"){<br /> obj.toString = hash.toString;<br /> }<br /> }<br /> return obj; // Object<br /> };<br /> function inherit(subClass, superClass) {<br /> var bridge = function() {};<br /> bridge.prototype = superClass.prototype;<br /> subClass.prototype = new bridge;<br /> subClass.prototype.constructor = subClass;<br /> subClass.prototype.superclass = superClass;<br /> return subClass;<br /> }<br /> var Animal = function(){<br /> this.name = "動物";<br /> };<br /> var Tiger = function(){}<br /> Tiger = inherit(Tiger,Animal)<br /> _mixin(Tiger.prototype,{<br /> name : "老虎",<br /> description:"獨居肉性大型貓科動物"<br /> //這樣這裡不樣重設構造器了<br /> })<br /> var t = new Tiger();<br /> alert(t.name)<br /> alert(t.description)<br /> var s = new t.superclass<br /> alert(s.name)<br />

運行代碼

但是這樣做還是不爽,因為我們還是需要手動設定var Tiger = function(){}這個空函數,這個下回再說。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.