說到面向對象這個破玩意,曾經一度我都處於很懵逼的狀態,那麼面向對象究竟是什麼呢?其實說白了,所謂面向對象,就是基於類這個概念,來實現封裝、繼承和多態的一種編程思想罷了。今天我們就來說一下這其中繼承的問題。 好,先不直接上代碼,而是反手來一波文字說明,捋一捋思路。 曾經一段時間因為javascript ...
說到面向對象這個破玩意,曾經一度我都處於很懵逼的狀態,那麼面向對象究竟是什麼呢?其實說白了,所謂面向對象,就是基於類這個概念,來實現封裝、繼承和多態的一種編程思想罷了。今天我們就來說一下這其中繼承的問題。
好,先不直接上代碼,而是反手來一波文字說明,捋一捋思路。
曾經一段時間因為javascript關於類實現繼承的不規範,導致各種各樣實現繼承的代碼;而實際上不管代碼怎麼變,繼承都基於兩種方式:
1.通過原型鏈,即子類的原型指向父類的實例從而實現原型共用。
2.借用構造函數,即通過js的apply、call實現子類調用父類的屬性、方法;
原型鏈方式可以實現所有屬性方法共用,但無法做到屬性、方法獨享(例如son1指向的是父類實例,son2,son3同樣如此,大家都是吃的同一碗飯);
而借用構造函數除了能獨享屬性、方法外還能在子類構造函數中傳遞參數,但代碼無法復用。總體而言就是可以實現所有屬性方法獨享,但無法做到屬性、方法共用(例如,son1新增了一個函數,然後想讓son2、son3一起用的話就無法實現了,只能son2,son3各自在構造函數中新增)。
組合繼承就是把以上兩種繼承方式一起使用,把共用的屬性、方法用原型鏈繼承實現,獨享的屬性、方法用借用構造函數實現,所以組合繼承幾乎完美實現了js的繼承;
為什麼說是“幾乎”?因為後來人們發現組合繼承有一個小bug,實現的時候調用了兩次父類,性能上不合格啊有木有!怎麼解決呢?於是“寄生繼承”就出來了。
簡單而言,寄生繼承就是不用實例化父類了,直接實例化一個臨時副本實現了相同的原型鏈繼承。(即子類的原型指向父類原型的副本),如此一來,這個問題就完美解決了。
接下來是代碼部分: 這裡我們通過apply方法給兒子傳了私有屬性,但是父類原型上的方法是無法調用的。 然後我們試試通過原型鏈來實現繼承。 這樣一來就把父類的全部東西都一股腦繼承下來了,而且我這裡如果Sons修改了父類的原型,其他跟著用的比如Daughters也要跟著遭殃。 而組合繼承這時候就出來了,組合繼承就是把以上兩種繼承方式一起使用,把共用的屬性、方法用原型鏈繼承實現;獨享的屬性、方法用借用構造函數實現。至於寄生組合繼承,它是為瞭解決組合繼承會二次調用父類這個bug出現的優化方法,具體實現如下: 在這一步,無論是兒子還是女兒,都能成功調用父類的公用方法。接著在末尾添加兩行代碼往下看: 兩個say方法雖然同名,卻互不影響。最後調用父類的私有屬性看看: 只有兒子利用私有屬性拿到了secret,而女兒沒有拿到,完美解決共用與獨享分配的問題!