javascript的六種繼承方式
1.原型鏈
function SuperType(){erty = true;}uperValue = function(){return erty;};function SubType(){roperty = false;}//繼承了otype = new SuperType();ubValue = function (){return roperty;};var instance = new SubType();alert(uperValue()); //true
實現的本質是重寫原型對象,代之以一個新類型的實例。
2.借用構造函數
function SuperType(){rs = ["red", "blue", "green"];}function SubType(){//繼承了(this);}var instance1 = new SubType();("black");alert(rs); //"red,blue,green,black"var instance2 = new SubType();alert(rs); //"red,blue,green"
如果僅僅是借用構造函數,那麼也將無法避免構造函數模式存在的問題——方法都在構造函數中定義,因此函數複用就無從談起了。而且,在超類型的原型中定義的方法,對子類型而言也是不可見的,結果所有類型都只能使用構造函數模式。考慮到這些問題,借用構造函數的技術也是很少單獨使用的。
3.組合繼承
function SuperType(name){ = name;rs = ["red", "blue", "green"];}ame = function(){alert();};function SubType(name, age){//繼承屬性(this, name); = age;}//繼承方法otype = new SuperType();tructor = SubType;ge = function(){alert();};var instance1 = new SubType("Nicholas", 29);("black");alert(rs); //"red,blue,green,black"ame(); //"Nicholas";ge(); //29var instance2 = new SubType("Greg", 27);alert(rs); //"red,blue,green"ame(); //"Greg";ge(); //27
在這個例子中,SuperType 構造函數定義了兩個屬性:name 和colors。SuperType 的原型定義了一個方法sayName()。SubType 構造函數在調用SuperType 構造函數時傳入了name 參數,緊接着又定義了它自己的屬性age。然後,將SuperType 的實例賦值給SubType 的原型,然後又在該新原型上定義了方法sayAge()。這樣一來,就可以讓兩個不同的SubType 實例既分別擁有自己屬性——包括colors 屬性,又可以使用相同的方法了。
組合繼承避免了原型鏈和借用構造函數的缺陷,融合了它們的優點,成爲JavaScript 中最常用的繼承模式。而且,instanceof 和isPrototypeOf()也能夠用於識別基於組合繼承創建的對象。
4.原型式繼承
function object(o){function F(){}otype = o;return new F();}
在object()函數內部,先創建了一個臨時性的構造函數,然後將傳入的對象作爲這個構造函數的原型,最後返回了這個臨時類型的一個新實例。從本質上講,object()對傳入其中的對象執行了一次淺複製。來看下面的例子。
var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = object(person); = "Greg";("Rob");var yetAnotherPerson = object(person); = "Linda";("Barbie");alert(nds); //"Shelby,Court,Van,Rob,Barbie"
克羅克福德主張的這種原型式繼承,要求你必須有一個對象可以作爲另一個對象的基礎。如果有這麼一個對象的話,可以把它傳遞給object()函數,然後再根據具體需求對得到的對象加以修改即可。在這個例子中,可以作爲另一個對象基礎的是person 對象,於是我們把它傳入到object()函數中,然後該函數就會返回一個新對象。這個新對象將person 作爲原型,所以它的原型中就包含一個基本類型值屬性和一個引用類型值屬性。這意味着nds 不僅屬於person 所有,而且也會被anotherPerson以及yetAnotherPerson 共享。實際上,這就相當於又創建了person 對象的兩個副本。
ECMAScript 5 通過新增te()方法規範化了原型式繼承。這個方法接收兩個參數:一個用作新對象原型的對象和(可選的)一個爲新對象定義額外屬性的對象。在傳入一個參數的情況下,te()與object()方法的行爲相同。
var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = te(person); = "Greg";("Rob");var yetAnotherPerson = te(person); = "Linda";("Barbie");alert(nds); //"Shelby,Court,Van,Rob,Barbie"
te()方法的第二個參數與neProperties()方法的第二個參數格式相同:每個屬性都是通過自己的`描述符定義的。以這種方式指定的任何屬性都會覆蓋原型對象上的同名屬性。例如:
var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = te(person, {name: {value: "Greg"}});alert(); //"Greg"
支持te()方法的瀏覽器有IE9+、Firefox 4+、Safari 5+、Opera 12+和Chrome。
在沒有必要興師動衆地創建構造函數,而只想讓一個對象與另一個對象保持類似的情況下,原型式繼承是完全可以勝任的。不過別忘了,包含引用類型值的屬性始終都會共享相應的值,就像使用原型模式一樣。
5.寄生式繼承
寄生式(parasitic)繼承是與原型式繼承緊密相關的一種思路,並且同樣也是由克羅克福德推而廣之的。寄生式繼承的思路與寄生構造函數和工廠模式類似,即創建一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來增強對象,最後再像真地是它做了所有工作一樣返回對象。以下代碼示範了寄生式繼承模式。
function createAnother(original){var clone = object(original); //通過調用函數創建一個新對象i = function(){ //以某種方式來增強這個對象alert("hi");};return clone; //返回這個對象}
在這個例子中,createAnother()函數接收了一個參數,也就是將要作爲新對象基礎的對象。然後,把這個對象(original)傳遞給object()函數,將返回的結果賦值給clone。再爲clone 對象添加一個新方法sayHi(),最後返回clone 對象。可以像下面這樣來使用createAnother()函數:
var person = {name: "Nicholas",friends: ["Shelby", "Court", "Van"]};var anotherPerson = createAnother(person);i(); //"hi"
這個例子中的代碼基於person 返回了一個新對象——anotherPerson。新對象不僅具有person的所有屬性和方法,而且還有自己的sayHi()方法。
在主要考慮對象而不是自定義類型和構造函數的情況下,寄生式繼承也是一種有用的模式。前面示範繼承模式時使用的object()函數不是必需的;任何能夠返回新對象的函數都適用於此模式。
使用寄生式繼承來爲對象添加函數,會由於不能做到函數複用而降低效率;這一
點與構造函數模式類似。
6.寄生組合式繼承
前面說過,組合繼承是JavaScript 最常用的繼承模式;不過,它也有自己的不足。組合繼承最大的問題就是無論什麼情況下,都會調用兩次超類型構造函數:一次是在創建子類型原型的時候,另一次是在子類型構造函數內部。沒錯,子類型最終會包含超類型對象的全部實例屬性,但我們不得不在調用子類型構造函數時重寫這些屬性。再來看一看下面組合繼承的例子。
function SuperType(name){ = name;rs = ["red", "blue", "green"];}ame = function(){alert();};function SubType(name, age){(this, name); //第二次調用SuperType() = age;}otype = new SuperType(); //第一次調用SuperType()tructor = SubType;ge = function(){alert();};
加粗字體的行中是調用SuperType 構造函數的代碼。在第一次調用SuperType 構造函數時,otype 會得到兩個屬性:name 和colors;它們都是SuperType 的實例屬性,只不過現在位於SubType 的原型中。當調用SubType 構造函數時,又會調用一次SuperType 構造函數,這一次又在新對象上創建了實例屬性name 和colors。於是,這兩個屬性就屏蔽了原型中的兩個同名屬性。圖6-6 展示了上述過程。
如圖6-6 所示,有兩組name 和colors 屬性:一組在實例上,一組在SubType 原型中。這就是調用兩次SuperType 構造函數的結果。好在我們已經找到了解決這個問題方法——寄生組合式繼承。
所謂寄生組合式繼承,即通過借用構造函數來繼承屬性,通過原型鏈的混成形式來繼承方法。其背後的基本思路是:不必爲了指定子類型的原型而調用超類型的構造函數,我們所需要的無非就是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,然後再將結果指定給子類型的原型。寄生組合式繼承的基本模式如下所示。
function inheritPrototype(subType, superType){var prototype = object(otype); //創建對象tructor = subType; //增強對象otype = prototype; //指定對象}
這個示例中的inheritPrototype()函數實現了寄生組合式繼承的最簡單形式。這個函數接收兩個參數:子類型構造函數和超類型構造函數。在函數內部,第一步是創建超類型原型的一個副本。第二步是爲創建的副本添加constructor 屬性,從而彌補因重寫原型而失去的默認的constructor 屬性。最後一步,將新創建的對象(即副本)賦值給子類型的原型。這樣,我們就可以用調用inherit-Prototype()函數的語句,去替換前面例子中爲子類型原型賦值的語句了,例如
function SuperType(name){ = name;rs = ["red", "blue", "green"];}ame = function(){alert();};function SubType(name, age){(this, name); = age;}inheritPrototype(SubType, SuperType);ge = function(){alert();};
這個例子的高效率體現在它只調用了一次SuperType 構造函數,並且因此避免了在otype 上面創建不必要的、多餘的屬性。與此同時,原型鏈還能保持不變;因此,還能夠正常使用instanceof 和isPrototypeOf()。開發人員普遍認爲寄生組合式繼承是引用類型最理想的繼承範式。
YUI 的nd()方法採用了寄生組合繼承,從而讓這種模式首次出現在了一個應用非常廣泛的JavaScript 庫中。要了解有關YUI 的更多信息,請訪問http://developer. 。
以上所述就是本文的全部內容了,希望對大家學習javascript繼承有所幫助。
相關文章
-
Javascript時間格式format函數的兩種使用方法
Javascript日期格式化在日常開發中還是挺常見的,那麼下面就給大家分享Javascript時間格式format函數的兩種使用方法示例,一起來看看。 方法一e=function(fmt) { var o = { "M+" : onth()+1, //月份 "d+" : ate(), // -
java與javascript之間json格式數據互轉詳解
老師們、同學們:早上好!今天我們全體師生齊聚在這裏,迎來了新學年的新學期。俗話說,新學期,新氣象,在此,我真誠地希望全體師生在新學期有新風貌!新收穫!新的學期開啓新的希望,新的憧憬承載新的夢想。爲了讓我們的夢想能成爲現實 -
JavaScript中調用函數的4種方式
1:方法調用模式var myObj = {//對象字面量 param1: 1, param2: 2, sum: function (){//this關鍵字只帶當前的對象retu lt = m1 + m2; }}(); //=>32:函數調用模式var add = function(a, b){ retu a + b;}//函數調用模式a -
Javascript 繼承實現例子參考
1. 創建基類首先考慮Polygon類。哪些屬性和方法是必需的?首先,一定要知道多邊形的邊數,所以應該加入整數屬性sides。還有什麼是多邊形必需的?也許你想知道多邊形的面積,那麼加入計算面積的方法getArea()。圖4-3展示了 -
javascript函數命名的三種方式及區別
第一複製代碼 代碼如下:function fn(val1,val2) {alert(val1+val2);}fn(1,2);第二複製代碼 代碼如下:var fn=function() {alert(val1+val2);}fn(1,2);第三複制代碼 代碼如下:var fn=new Function("alert(val1+val2)") -
關於JavaScript中繼承的深入理解
JavaScript中我們可以藉助原型實現繼承。例如function baz(){="";}function foo(){}otype=new baz();var myFoo=new foo();;這樣我們就可以訪問到baz裏的屬性oo啦。在實際使用中這個樣不行滴,由於原型的共享特點(數據保 -
關於 response方法的javascript asp教程第六課
response 對象:reponse是asp中六個對象之一。它代表了服務器端對瀏覽器的迴應。response有8種方法,9種屬性和一個集。在這一課,我們就重點講述方法。方法:在javascript中,asp方法使用括號。請注意依賴er的兩個方法,我們將在 -
深入理解Javascript的繼承和原型鏈
在上一篇文章中,介紹了原型的概念,瞭解到在javascript中構造函數、原型對象、實例三個好基友之間的關係:每一個構造函數都有一個“守護神”——原型對象,原型對象心裏面也存着一個構造函數的“位置”,兩情相悅,而實例呢卻又 -
理解JavaScript中的封裝與繼承特性
JavaScript中的封裝封裝簡單地說就是讓外界只能訪問對象的共有變量和函數,隱藏細節和數據。js中有三種方法創建對象,分別爲門戶大開型、用命名規範區分私有變量、閉包創建真正的私有變量三種。1.門戶大開型,是實現對 -
使用JavaScript實現Java的List功能
複製代碼 代碼如下:/*** js模擬java中的List*/var list = new Array();/*** 添加* @param {Object} object*/function add(object) {list[th] = object;}/*** 移除此列表中指定位置上的元素。* @param index 指定位置