程式的開發離不開程式碼的複用,通過程式碼複用可以減少開發和維護成本,在談及程式碼複用的時候,會首先想到繼承性,但繼承並不是解決程式碼複用的唯一方式,還有其他的複用模式比如物件組合。本節將會講解多種繼承模式以實現程式碼複用。
- 繼承複用-預設模式
- 繼承複用-apply函式
- 繼承複用-臨時構造
繼承複用之預設模式:
每個javascript物件都和另一個物件 相關聯,而這個物件就是原型(prototype),而原型又可以連結到其他原型行程原型鏈,如果當前物件不存在類似方法則會沿原型鏈查詢,直到查詢為止。繼承的預設模式即通過這種原型鏈的特性實現的。
Person類為基類定義了一些屬性和方法
/** * person 基類 */ var Person = function () { this.name = ""; this.age = 0; this.sex = ""; this.say = function () { return "my name is" + this.name; } } Person.prototype.sayHello = function () { return "Hello"; }
定義一個空的子函式物件
/** * 原型繼承 */ var Engineer1 = function () { }
將子物件的原型鏈中加入父類和父類原型
Engineer1.prototype = new Person(); var enginneer1 = new Engineer1(); enginneer1.name = 'stephen'; console.log(enginneer1.say());
此類繼承實現缺點:
不能傳遞構造的引數:假設person基類中可以接受構造傳參,而繼承的子類想通過父類構造傳遞引數則是不可行的。
繼承複用-apply函式
apply函式定義:用於呼叫當前函式functionObject
,並可同時使用指定物件thisObj
作為本次函式執行時函式內部的this
指標引用。通俗的講,就是將當前函式物件的成員複製到this所引用的函式物件中去。
可以在子類構造中通過apply方法將父類的成員複製到子類中,而且可以通過apply傳遞引數,而不是繫結原型鏈,
var Engineer2 = function () { Person.apply(this); }
相反由於不是繫結原型鏈因此如果在父類原型中的方法是不能被繼承的 ,如下程式碼所示
Person.prototype.sayHello = function () { return "Hello"; }
使用示例
var enginner2 = new Engineer2(); enginner2.name = 'adam'; console.log(enginner2.say());
繼承複用-臨時構造
上面兩種方法各有優劣,但都不完美,預設繼承不能傳遞構造的引數,而通過Apply()函式的構造繫結又不能繼承父類原型鏈的方法,而且有時基類有私有的方法不想被子類繼承,以上兩種都不能做到。而臨時建構函式的方法能得到一個比較完美的解決方案。
首先生成一個臨時函式物件,通過原型鏈共享將臨時函式物件的原型鏈指定為父類原型鏈(注意這裡不是繫結哦),接著將子類的原型鏈繫結上臨時函式的原型鏈。
var temp = function (){}; temp.prototype = Person.prototype; Engineer1.prototype = new temp(); var enginner3 = new Engineer1(); enginner3.name = "stphen"; console.log(enginner3.say());
通過上面程式碼的處理,子物件擁有了臨時函式的原型鏈,卻沒有繼承父類在函式中定義的成員,這樣如果想要定義私有的方法則可以在函式定義中,如果想定義可繼承方法可在函式prototype中,從而比較完美的解決繼承。
小結:
在javascript中實現繼承有許多方法,在本節中講解了三種主要的方法,每種方法繼承都有各自的優勢和缺點,可以在開發專案時約定使用某一種方式,當然除了繼承外還可以使用apply借用某一個方法從而達到複用的目的,畢竟為了使用某一個方法而建立長長的原型鏈並不是一種可取的方式。
參考內容
《javascript 模式》 stoyan stefanov