javascript實現的繼承的幾種常用方式
作為一門物件導向的語言,繼承自然是一大特徵之一。
但是javascript並不是一門像c#或者java一樣特別標準的物件導向的語言(當前來說)。
所以實現繼承方式也是多種多樣,下面就簡單分享一下常用的幾種方式,需要的朋友可以做一下參考。
一.原型鏈方式:
[JavaScript] 純文字檢視 複製程式碼function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //繼承了SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); console.log(instance.getSuperValue()); //true
實現的本質是重寫原型物件,代之以一個新型別的例項。
二.借用建構函式方式:
[JavaScript] 純文字檢視 複製程式碼function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ //繼承了SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); console.log(instance2.colors); //"red,blue,green"
如果僅僅是借用建構函式,那麼也將無法避免建構函式模式存在的問題——方法都在建構函式中定義,因此函式複用就無從談起了。而且,在超型別的原型中定義的方法,對子型別而言也是不可見的,結果所有型別都只能使用建構函式模式。考慮到這些問題,借用建構函式的技術也是很少單獨使用的。
三.組合繼承方式:
[JavaScript] 純文字檢視 複製程式碼function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ console.log(this.name); }; function SubType(name, age){ //繼承屬性 SuperType.call(this, name); this.age = age; } //繼承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ console.log(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); console.log(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); console.log(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
在這個例子中,SuperType 建構函式定義了兩個屬性:name 和colors。SuperType 的原型定義了一個方法sayName()。SubType 建構函式在呼叫SuperType 建構函式時傳入了name 引數,緊接著又定義了它自己的屬性age。然後,將SuperType 的例項賦值給SubType 的原型,然後又在該新原型上定義了方法sayAge()。這樣一來,就可以讓兩個不同的SubType 例項既分別擁有自己屬性——包括colors 屬性,又可以使用相同的方法了。
組合繼承避免了原型鏈和借用建構函式的缺陷,融合了它們的優點,成為JavaScript 中最常用的繼承模式。而且,instanceof 和isPrototypeOf()也能夠用於識別基於組合繼承建立的物件。
四.原型式繼承:
[JavaScript] 純文字檢視 複製程式碼function object(o){ function F(){} F.prototype = o; return new F(); }
在object()函式內部,先建立了一個臨時性的建構函式,然後將傳入的物件作為這個建構函式的原型,最後返回了這個臨時型別的一個新例項。從本質上講,object()對傳入其中的物件執行了一次淺複製。來看下面的例子。
[JavaScript] 純文字檢視 複製程式碼var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); console.log(person.friends); //"Shelby,Court,Van,Rob,Barbie"
克羅克福德主張的這種原型式繼承,要求你必須有一個物件可以作為另一個物件的基礎。如果有這麼一個物件的話,可以把它傳遞給object()函式,然後再根據具體需求對得到的物件加以修改即可。在這個例子中,可以作為另一個物件基礎的是person 物件,於是我們把它傳入到object()函式中,然後該函式就會返回一個新物件。這個新物件將person 作為原型,所以它的原型中就包含一個基本型別值屬性和一個引用型別值屬性。這意味著person.friends 不僅屬於person 所有,而且也會被anotherPerson以及yetAnotherPerson 共享。實際上,這就相當於又建立了person 物件的兩個副本。
ECMAScript 5 通過新增Object.create()方法規範化了原型式繼承。這個方法接收兩個引數:一個用作新物件原型的物件和(可選的)一個為新物件定義額外屬性的物件。在傳入一個引數的情況下,Object.create()與object()方法的行為相同。
[JavaScript] 純文字檢視 複製程式碼var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = Object.create(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); console.log(person.friends); //"Shelby,Court,Van,Rob,Barbie"
Object.create()方法的第二個引數與Object.defineProperties()方法的第二個引數格式相同:每個屬性都是通過自己的描述符定義的。以這種方式指定的任何屬性都會覆蓋原型物件上的同名屬性。例如:
[JavaScript] 純文字檢視 複製程式碼var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = Object.create(person, { name: { value: "Greg" } }); console.log(anotherPerson.name); //"Greg"
支援Object.create()方法的瀏覽器有IE9+、Firefox 4+、Safari 5+、Opera 12+和Chrome。
在沒有必要興師動眾地建立建構函式,而只想讓一個物件與另一個物件保持類似的情況下,原型式繼承是完全可以勝任的。不過別忘了,包含引用型別值的屬性始終都會共享相應的值,就像使用原型模式一樣。
五.寄生式繼承:
寄生式(parasitic)繼承是與原型式繼承緊密相關的一種思路,並且同樣也是由克羅克福德推而廣之的。寄生式繼承的思路與寄生建構函式和工廠模式類似,即建立一個僅用於封裝繼承過程的函式,該函式在內部以某種方式來增強物件,最後再像真地是它做了所有工作一樣返回物件。以下程式碼示範了寄生式繼承模式。
[JavaScript] 純文字檢視 複製程式碼function createAnother(original){ var clone = object(original); //通過呼叫函式建立一個新物件 clone.sayHi = function(){ //以某種方式來增強這個物件 console.log("hi"); }; return clone; //返回這個物件 }
在這個例子中,createAnother()函式接收了一個引數,也就是將要作為新物件基礎的物件。然後,把這個物件(original)傳遞給object()函式,將返回的結果賦值給clone。再為clone 物件新增一個新方法sayHi(),最後返回clone 物件。可以像下面這樣來使用createAnother()函式:
[JavaScript] 純文字檢視 複製程式碼var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi"
這個例子中的程式碼基於person 返回了一個新物件——anotherPerson。
新物件不僅具有person的所有屬性和方法,而且還有自己的sayHi()方法。
在主要考慮物件而不是自定義型別和建構函式的情況下,寄生式繼承也是一種有用的模式。
前面示範繼承模式時使用的object()函式不是必需的。
任何能夠返回新物件的函式都適用於此模式。
使用寄生式繼承來為物件新增函式,會由於不能做到函式複用而降低效率,這一點與建構函式模式類似。
相關文章
- JavaScript的幾種繼承方式JavaScript繼承
- 實現繼承的幾種方式及工作原理繼承
- JavaScript實現繼承的方式JavaScript繼承
- Javascript 五十問——實現的繼承多種方式JavaScript繼承
- js實現繼承的幾種方式和對比JS繼承
- Javascript 中實現物件原型繼承的三種方式JavaScript物件原型繼承
- javascript幾種繼承方式;不看就out啦JavaScript繼承
- JavaScript 中的六種繼承方式JavaScript繼承
- js實現繼承的三種方式JS繼承
- JS 繼承的 六 種實現方式JS繼承
- 原型鏈實現繼承的6種方式原型繼承
- 深入 JavaScript 常用的8種繼承方案JavaScript繼承
- 繼承的實現方式繼承
- JavaScript常用八種繼承方案JavaScript繼承
- 實現 JavaScript 沙箱的幾種方式JavaScript
- JS 總結之原型繼承的幾種方式JS原型繼承
- JavaScript繼承的多種方式和優缺點JavaScript繼承
- 實現JavaScript繼承JavaScript繼承
- 你知道JavaScript的繼承有幾種寫法嗎?JavaScript繼承
- JavaScript中的六種繼承JavaScript繼承
- 物件導向:類的定義和繼承的幾種方式物件繼承
- 6種JavaScript繼承方式及優缺點JavaScript繼承
- Javascript如何實現繼承JavaScript繼承
- JavaScript物件導向—繼承的實現JavaScript物件繼承
- 三種繼承方式繼承
- JS中的多種繼承方式JS繼承
- JavaScript 各種繼承方式優缺點對比JavaScript繼承
- 幾種常用的排序演算法之JavaScript實現排序演算法JavaScript
- JavaScript中的繼承及實現程式碼JavaScript繼承
- [JS]繼承的這6種方式!(上)JS繼承
- [JS]繼承的這6種方式!(下)JS繼承
- 細說 js 的7種繼承方式JS繼承
- Web前端------JS高階繼承的實現方式Web前端JS繼承
- Javascript實現物件導向繼承JavaScript物件繼承
- 面對面講述JavaScript之繼承的實現JavaScript繼承
- Javascript繼承4:潔淨的繼承者—-原型式繼承JavaScript繼承原型
- JavaScript中的繼承JavaScript繼承
- JS中的多種繼承方式(第12天)JS繼承
- 實現登入態的幾種方式