標籤:
繼承,同樣不是真正嚴格意義上物件導向的繼承,而是通過javascript中的原型鏈關係實現函數之間的屬性,方法共用.下面簡單分享幾種封裝的方法.
既然說到繼承,我們必須有一個基類
1 2 3 4 5 6 7 8 9 |
function Person(){ this.eat=function(){ return ‘吃食物‘; } } Person.prototype.sport=function(){ return ‘運動‘; } |
Person 這個基類包含了2個屬性,吃和運動.但是奇怪的是在建構函式(當然是類比的)中定義了一個屬性 eat ,我們賦值了一個方法,方法返回吃食物.
然後又在Person 類的原型上定義了一個屬性 sport ,賦值一個方法,返回運動.
其實這2個屬性完全可以都放在 建構函式,或者全部定義在原型對象上,沒有問題,我們這裡分別定義只是為了示範後面子類繼承基類後執行個體化的對象能不能100%繼承基類裡定義的這2種方式呢? 我們下面一一舉例查看.
(一)第一種繼承方式,建構函式裡綁定
下面我要定義一個子類,學生,讓學生繼承人,並且在學生的建構函式裡綁定基類 Person
1 2 3 4 |
function Student(name){ Person.apply(this,arguments); this.name=name; } |
如何?的綁定,就是javascript中的 apply 和 call 方法,這2個方法實現目的相同,只是參數格式不一樣,看這裡 call 和 apply 實現繼承的區別
我用JS Runner 來示範一下,為了在工具下方列印出來,重寫了 print 函數:
1 2 3 4 5 6 7 |
var print=function(text){ var t=‘‘; for(item in arguments){ t+= arguments[item]+‘,‘; } document.write(t+‘<br/>‘); } |
你可以不關註上面這個函數,如果你在chrome 的控制台調試, mac下 option + command +i 即可掉出來,用 console.log 就可以輸出結果.
紅框是工具方法,為了在下發列印出來,重寫了 print 方法.
藍框是基類 Person
綠框是子類 Student
黑框是輸出語句, name 屬性和 study() 方法是子類定義的.列印沒有問題, eat() 方法是基類定義,看了繼承了基類這個方法,但是基類還有一個原型上的方法 sport() ,我們再來看下這個方法. xiaoming.sport() ,結果報錯,如下:
1 |
TypeError: undefined is not a function (evaluating ‘xiaoming.sport()‘) |
到這裡你就看到了建構函式綁定的弊端了,它是有局限的,在子類 建構函式裡綁定基類,只能繼承來自基類建構函式定義的屬性,方法,對於基類原型 prototype 對象上定義的屬性,方法都是不能被子類繼承的.
(二)子類原型繼承基類
還是剛才的例子,Student 的原型就是 Student.prototype
1 |
Student.prototype=new Person(); |
這一句的含義就是把子類原型指標指向基類的執行個體.這樣也可以繼承基類的屬性方法.
和上面的圖不同的有2個地方,紅框部分是子類繼承基類,列印的時候最後把基類的2個方法都列印出來了.
看上去相當完美,基類建構函式的屬性和基類原型鏈上的屬性統統能繼承.
(三) 子類原型繼承基類原型
和上面的方法大同小異,區別就是把上面基類的對象變成了基類的原型
上面圖片和第一幅圖片有2處差異,紅框處 Student.prototype 繼承了 基類 Person.prototype
綠框處輸出了子類的所有屬性,方法,但是,基類的方法只有原型上的可以輸出,我們嘗試輸出 xiaoming.eat(); 結果報錯:
1 |
32 TypeError: undefined is not a function (evaluating ‘xiaoming.eat()‘) |
子類原型繼承基類原型過程中,基類建構函式定義的屬性,方法都將不會繼承到子類.
javascript 中物件導向實現 如何繼承