JavaScript繼承
原型鏈繼承
function SuperType() { this.property = true; } //在原型鏈上定義方法。 SuperType.prototype.getSuperValue = function (){ return this.property; } function SubType() { this.subproperty = false; } //替換SubType原型,達到繼承效果。 SubType.prototype = new SuperType(); //開始寫SubType的方法,注:SubType的方法必須寫在替換SubType原型語句後 SubType.prototype.getSubValue = function (){ return this.subproperty; } var instance = new SubType(); alert(instance.getSuperValue());
原型鏈繼承的原理如期名,是利用建立父類(SuperType)的例項,並將該例項賦值給子類(SubType).prototype實現的,實質是重寫子類的原型物件。
原型鏈繼承特點:
- 引用型別值的原型屬性會被所有例項共享。
- 在建立子型別的例項時,沒辦法再不影響所有物件例項的情況下向超類傳遞引數。
- 即實現 所有屬性方法共享,但無法做到屬性、方法獨享 。
借用建構函式繼承
function SuperType() { this.colors = ['red','blue','green']; } function SubType() { //繼承屬性 SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push('black'); alert(instance1.colors);//red,blue,green,black var instance2 = new SubType(); alert(instance2.colors);//red,blue,green
借用建構函式繼承(constructor stealing),該繼承思想很簡單,即在子型別建構函式的內部呼叫超型別建構函式即可。通過call()方法(或apply()方法也可以),實質上是在(未來將要)新建立的SubType例項的環境下呼叫SuperType建構函式。
借用建構函式繼承特點:
- 可以在子型別建構函式中向超型別建構函式傳遞引數。
- 方法都在建構函式中定義,無法實現函式複用。
- 超型別的原型中定義的方法對子類不可見。
- 即實現 所有屬性獨享,但無法做到方法繼承 。
組合繼承
function SuperType(name) { this.name = name; this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function () { alert(this.name); } function SubType(name,age) { //繼承屬性 SuperType.call(this,name);//第二次呼叫SuperType this.age = age; } //繼承方法 SubType.prototype = new SuperType();//第一次呼叫SuperType SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); } var instance1 = new SubType('Y',21); instance1.colors.push('black'); alert(instance1.colors);//red,blue,green,black instance1.sayName();//Y instance1.sayAge();//21 var instance2 = new SubType('Z',22); alert(instance2.colors);//red,blue,green instance2.sayName();//Z instance2.sayAge();//22
組合繼承(combination inheritance)又叫偽經典繼承,是JavaScript中最常用的繼承模式。組合繼承指的是將原型鏈繼承和借用建構函式繼承的技術組合到一塊,從而發揮二者之長的一種繼承模式。該模式通過借用建構函式繼承屬性,通過重新子型別prototype繼承方法。
組合繼承特點:
- 實現了 所有方法共享,屬性獨享 。
- instanceof()和isprototypeOf()能夠識別基於組合繼承建立的物件。
- 實現的時候呼叫了兩次超類(父類),產生多餘屬性。
原型式繼承
//工具函式,實質是對傳入的物件執行一次淺拷貝。 function object(o) { function F() {} F.prototype = o; return new F(); } var person = { name:'Y', friends:['S','C','V'], say:function () { alert(this.friends); } }; var anotherPerson = object(person); anotherPerson.name = 'G'; anotherPerson.friends.push('R'); var yetAnotherPerson = object(person); yetAnotherPerson.name = 'L'; yetAnotherPerson.friends.push('B'); person.friends.push('my'); anotherPerson.say();//S,C,V,R,B,my alert(person.friends);//S,C,V,R,B,my
原型式繼承是由道格拉斯·克羅克福德提出的,該模式要求你必須有一個物件可以作為另外一個物件的基礎。該模式將一個物件傳遞給object()函式,然後再根據具體需求對得到的物件加以修改即可。
原型式繼承特點:
- 以傳入object的物件為原型,拷貝一個副本並反回。
- 做不到函式複用,導致效率低。
- 物件的引用型別所有例項共享 (person的引用型別friends不僅屬於person所有,而且也會被antherPerson和yetAnotherPerson共享)。
寄生式繼承
function object(o) { function F() {} F.prototype = o; return new F(); } function createAnother(original) { var clone = object(original); clone.sayHi = function (){ alert(this.friends); }; return clone; } var person = { name:'Y', friends:['S','C','V'] }; var anotherPerson = createAnother(person); anotherPerson.friends.push('test'); anotherPerson.sayHi(); var anotherPerson2 = createAnother(person); anotherPerson2.sayHi();
寄生式繼承(parasitic)同樣是由克羅克福德提出並推廣而之的。該模式建立一個僅用於封裝繼承過程的函式,該函式的內部以某種方式增強物件,最後再像真地式它做了所有工作一樣返回物件。
寄生式繼承特點:
- 做不到函式複用,導致效率低。
- 物件的引用型別所有例項共享 。
寄生組合式繼承
function object(o) { function F() {} F.prototype = o; return new F(); } //將超型別的prototype淺拷貝一遍並賦值給子型別的prototype //(相當於利用超型別prototype重寫子型別prototype以達到繼承效果) function inheritPrototype(subType,superType) { var prototype = object(superType.prototype); prototype.constructor = subType; subType.prototype = prototype; } function SuperType(name) { this.name = name; this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function () { alert(this.name); } function SubType(name,age) { //繼承屬性 SuperType.call(this,name); this.age = age; } //繼承方法 inheritPrototype(SubType,SuperType); SubType.prototype.sayAge = function(){ alert(this.age); } var instance1 = new SubType('Y',21); instance1.colors.push('black'); alert(instance1.colors);//red,blue,green,black instance1.sayName();//Y instance1.sayAge();//21 var instance2 = new SubType('Z',22); alert(instance2.colors);//red,blue,green instance2.sayName();//Z instance2.sayAge();//22
原理如圖:
寄生組合式繼承解決了組合繼承最大的問題——無論什麼情況下,都會呼叫兩次超型別建構函式。該模式思路是:不必為了指定子型別的原型而呼叫超型別的建構函式,我們所需的無非就是超型別原型的副本而已。本質上,就是使用寄生式繼承來繼承超型別的原型,然後再將結果指定給子型別的原型。
寄生組合式繼承特點:
- 實現了 所有方法共享,屬性獨享 。
- instanceof()和isprototypeOf()能夠識別基於組合繼承建立的物件。
參考自《JavaScript高階程式設計》