前言: 寫到這裏,差很少就把OOP完結了,寫了幾篇OOP的文章,可是隻是略懂皮毛,可能深刻的OOP還有不少,可是我感受寫到這裏也算是差很少完結了。數組
繼承函數
繼承是面向對象比較核心的概念,其餘語言可能實現繼承有兩種方式:接口,繼承。而ECMAscript只有繼承。this
原型鏈繼承prototype
通俗的講,就是經過構造函數的原型對象去繼承父類。上一篇文章咱們說過。繼承最大的優勢也是缺點就是共享,看代碼:code
function First() { //建立一個構造函數(做爲父類) this.a = 'abc'; //添加屬性 } function Second() { //另外一個構造函數(做爲派生類也稱爲子類) this.b = '10'; //同上 } Second.prototype = new First(); //子類的原型對象添加父類的實例。 var box = new Second(); //實例化並賦值給一個變量 alert(box.a); //返回abc
你們看的出,第二個構造函數內並無a這個屬性,可是咱們從原型去添加一個父類的實例化,就能繼承父類的構造體內的和原型對象。對象
Second構造函數經過原型繼承了First構造函數和原型,這就造成了一個鏈條,通俗的講就是:原型鏈繼承。繼承
也能夠這麼說,用對象實例化賦值給子類的原型屬性,會將父類的構造函數裏面的信息和原型裏面的信息都交給子類。接口
仍是那句話,字面量重寫原型會中斷關係,使用引用類型的原型,而且子類型還沒法給超類型傳遞參數。ip
對象冒充原型鏈
不知道你們發現沒有,父類是沒法傳參的,並且引用共享的問題,咱們可使用對象冒充的方法去實現繼承。
function First (b) { //建立一個構造函數並傳參 this.a = ['a','b','c']; //添加一個屬性爲一個數組 this.b = b; //添加屬性獲得傳進去的值 } function Second (b) { //同上 First.call(this,b); //對象冒充 } var second = new Second(100); //實例化子類並賦值給變量 alert(second.a); //返回a,b,c alert(second.b); //返回100
從上面的代碼咱們能夠看出,咱們解決了父類傳參問題,也解決了引用共享問題。可是沒有原型。並且call方法只能冒充構造函數裏面的屬性和方法而沒法冒充原型對象裏面的屬性和方法
還有最大的問題就是重複使用。
咱們來用代碼證實上面的話,就是call冒充只是冒充構造函數裏面的方法和屬性。
/*alert(second.a); 返回a,b,c */ second.a.push('d'); //給數組末尾添加一個d alert(second.a); //返回a,b,c,d
從上面代碼看出,並無繼承原型,也就是共享。重複使用更是不可能的。
原型鏈+冒充
固然咱們能夠變通一下,將上面兩種方法結合一下不就達到效果了麼!咱們大概的思想是該私有化的屬性和方法就私有化,該共享的公有化的方法就放在原型裏面不就得了!
function First (b) { this.a = ['a','b','c']; this.b = b; } First.prototype.c = function () { //公有化方法放在原型中 return this.a + this.b; }; function Second (b) { First.call(this,b); //對象冒充 } Second.prototype = new First(); //子類的原型對象添加父類的實例 var second = new Second(100); //實例化並賦值給變量 alert(second.c()); 返回a,b,c10
從上面的例子用能夠看出,咱們將咱們不想共享的屬性和方法放在構造函數中,而咱們想私有化的方法放在原型對象中,達到了清晰代碼的做用,並且解決了重複使用和傳參的問題而且有了原型!
總結:
說了這麼多,其實Javascript中實現繼承是十分靈活的,並無一種最好的方法,須要根據不一樣的需求實現不一樣方式的繼承,最重要的是要理解Javascript中實現繼承的原理,也就是原型和原型鏈的問題,只要理解了這些,本身也就能夠很輕鬆實現繼承了。
Brian.Lee