繼承是面嚮對象語言一個很是重要的部分。許多OOP語言都支持接口繼承和實現繼承兩種方式。接口繼承:繼承方法簽名;實現繼承:繼承實際的方法。在ECMAScript中函數是沒有簽名的,因此也就沒法實現接口繼承,只能支持實現繼承。編程
在JavaScript中有大概六種繼承方式,它們分別是:原型鏈繼承,借用構造函數繼承,組合繼承,原型式繼承,寄生式繼承和寄生組合式繼承。下面就是對着六種繼承方式的詳細介紹。函數
基本思想是利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。在這裏還得補充一下,每一個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含一個指向原型對象的內部指針。測試
function BasicType() { this.property=true; this.getBasicValue = function(){ return this.property; }; } function NewType() { this.subproperty=false; } NewType.prototype = new BasicType(); var test = new NewType(); alert(test.getBasicValue()); //true
由上面能夠知道,其本質上是重寫了原型對象,代之一個新類型的實例。在經過原型鏈繼承的狀況下,要訪問一個實例屬性時,要通過三個步驟:1搜索實例;2搜索NewType.prototype;3搜索BasicType.prototype,此時才找到方法。若是找不到屬性或者方法,會一直向上回溯到末端纔會中止。要想肯定實例和原型的關係,可使用instanceof和isPrototypeof()測試,只要是原型鏈中出現過的原型,均可以說是該原型鏈所派生實例的原型。還有一點須要注意,經過原型鏈實現繼承時,不能使用對象字面量建立原型方法,由於這時會重寫原型鏈,原型鏈會被截斷。this
其大致思路是,在子類型構造函數的內部調用超類型構造函數。spa
function BasicType(name) {
this.name=name; this.color=["red","blue","green"]; } function NewType() { BasicType.call(this,"syf");
this.age=23; } var test = new NewType();
alert(text.name); //syf
alert(text.age); //23
這種繼承實現方式有一種優點就是,能夠在子類型構造函數中向超類型構造函數中傳遞參數,其缺點是不能進行函數複用。prototype
組合繼承就是將原型鏈和借用構造函數繼承模式結合起來,從而具備兩者優點的方法。其理念是使用原型鏈實現對原型屬性和方法的繼承,經過借用構造函數來實現對實例屬性的繼承。指針
function BasicType(name) { this.name=name; this.colors=["red","blue","green"]; } BasicType.prototype.sayName=function(){ alert(this.name); } function NewType(name,age) { BasicType.call(this,name); this.age=age; } var test = new NewType("syf","23"); test.colors.push("black"); alert(test.colors); //"red,blue,green,black" alert(test.name); //"syf" alert(test.age); //23
組合式繼承避免了原型鏈和借用構造函數繼承方式的缺陷,融合了他們的優勢,成爲了js中最經常使用的繼承方式。code
原型鏈繼承和原型式繼承只有一字之差,但他們的機理仍是有所差異的。原型式繼承是藉助於已有的對象來建立新對象,也就是必須有一個對象能夠做爲另一個對象的基礎。繼承方式函數表達爲:對象
function object (o) { function F(){} F.prototype = o; return new F(); }
咱們能夠在o的基礎上進行修改,來建立特定的對象。直觀上來講,其與原型鏈繼承最大的不一樣之處就是沒有使用new操做符。blog
寄生式繼承的思路與寄生構造函數和工廠模式相似,即建立一個僅用於封裝繼承過程的函數,該函數在內部以某種方式來繼承對象,最後再返回對象。具體爲:
function createAnother ( original ){ var clone = object (original); //經過調用函數建立一個新對象 clone.sayHi=function(){ //以某種方式來加強這個對象 alert("hi"); }; return clone; //返回對象 }
在主要考慮對象而不是自定義類型和構造函數的狀況下,寄生式繼承也是一種有用的模式。使用寄生式繼承來爲對象添加函數,函數複用率低。
上面提到組合式繼承,其也是JS裏最經常使用的基礎模式。但,因爲其會調用兩次超類型的構造函數:一次在建立子類型的時候,另外一次是在子類型構造函數內部。也就是子類型最終會包含超類型的所有實例屬性,但在調用子類型構造函數時會重寫這些屬性。寄生組合式繼承的大體思路爲:經過借用構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法。也就是說,沒必要爲了指定子類型的原型而調用超類型的構造函數,咱們須要的是超類型原型的一個副本而已。本質上就是,使用寄生式繼承來繼承超類型的原型,而後再將結果指定給子類型的原型。基本模式以下:
function inheritPrototype (subType ,superType){ var prototype = object (superType.prototype); //建立對象,建立超類型原型的一個副本 prototype.constructor = subType; //加強對象,爲建立的副本添加constructor屬性
subType.prototype = prototype; //指定對象,將新建立的對象賦值給子類型的原型
}
因爲寄生組合式繼承彌補了組合式繼承缺點,因此也被衆多開發者認爲是最理想的繼承方式。
以上就是JS裏的六種繼承方式的介紹,在編程實踐中具體選取哪一種方式還要根據當時狀況來斷定,適合的纔是最好的,並必定非得使用組合式繼承或者寄生組合式繼承來完成繼承。