咱們都知道,面向對象的編程語言很是強大,之因此強大,就是其支持繼承。在JavaScript中,也支持繼承,並且有多種方法實現繼承,好比原型鏈繼承,借用構造函數繼承,或者把原型鏈和借用構造函數函數組合在一塊兒的組合繼承,還有直接原型式繼承,深淺拷貝繼承。下面我就一一來講一說這些繼承方法。javascript
首先咱們得清楚構造函數(constructor),原型對象(prototype)和實例的三者關係。html
每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。java
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //inherit from SuperType SubType.prototype = new SuperType();//重寫原型對象,賦值爲一個實例對象,得到實例對象的全部屬性和方法 SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true
原型鏈的詳細請看深刻理解原型鏈一文編程
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ //inherit from SuperType 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"
經過借用構造函數的方法,會實現對實例屬性的繼承,每一個實例都有它本身的屬性,這些屬性都是部署在本身身上的,每個實例對象都有本身的一個副本。改變屬性不會對其它實例對象的該屬性形成影響。數組
組合繼承,有時候也叫僞經典繼承,指的是將原型鏈和借用構造函數的技術組合到一塊,從而發揮兩者之長的一種繼承模式。其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而經過借用構造函數來實現對實例屬性的繼承。這樣既經過在原型上定義方法實現了函數複用,又可以保證每一個實例都有它本身的屬性。編程語言
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; } SubType.prototype = new SuperType();//原型鏈實現對原型屬性和方法的繼承,這樣它的實例實例對象都會繼承原型屬性方法,都至關因而指針引用,除非本身重寫了一個相同的屬性或者方法實現覆蓋,不然修改熟悉就會出現原型鏈中德問題 SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27`
原型式繼承並無使用嚴格意義上的構造函數,而是藉助原型能夠基於已有的對象建立新對象,同時還沒必要建立自定義類型。函數
function object(o) { function F() {} F.prototype = o; return new F(); }
在object()函數內部,先建立了一個臨時性的構造函數,而後將傳入的對象做爲這個構造函數的原型,最後返回了這個臨時類型的一個新實例。本質上,是對傳入其中的對象作了一次淺拷貝。this
實例prototype
function object(o){ function F(){} F.prototype = o; return new F(); } 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"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
原型式繼承要求你必須有一個對象做爲另外一個對象的基礎,經過把一個對象傳遞給object()函數,而後再根據具體需求對獲得的對象加以修改(修改原來的,或者添加新的屬性方法)便可。指針
在ECMAScript5中,新增了一個Object.create()方法規範了原型式繼承,這個方法接受兩個參數:一個用做新對象原型的對象和(可選的)一個爲新對象定義額外屬性的對象。在傳入一個參數的狀況下,Object.create()與object()方法的行爲相同。
實例
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"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"