JavaScript面向?qū)ο缶幊蹋涸屠^承實例
JavaScript不是純的面向?qū)ο蟮恼Z言,而是基于對象的語言,對象的繼承是以原型函數(shù)的形式繼承的,下面我們將主要介紹用JavaScript寫出面向?qū)ο缶幊棠J降牡囊粋€小例子。
推薦閱讀:淺談JavaScript中面向?qū)ο蠹夹g(shù)的模擬
創(chuàng)建基類
***個我們需要創(chuàng)建一個基類來實例化操作。New后面的標識符是對象的constructor,任意一個javascript類都可以這樣創(chuàng)建這樣一個實例。舉個例子,下面的代碼創(chuàng)建了一個person類,然后實例化一個person對象。
- function Person(first, last) {
 - this.first = first;
 - this.last = last;
 - }
 - var person = new Person(“John”, “Dough”);
 
添加方法
如果你想在類上添加方法來操作這個類的實例,就像這樣,我們就可以通過創(chuàng)建”toString”方法去展示對象里的內(nèi)容。在我們的基類上這樣實現(xiàn)。
- Person.prototype.toString = function() {
 - return this.first + ” ” + this.last;
 - };
 - alert( person ); // displays “John Dough”
 
這證明了JavaScript語言的一個特性,“原型”。簡單的說,所有JavaScript對象都有一個私有的原型屬性(_proto_)。這個”私有”意味著這個屬性不可見或者只有對象本身可以訪問。當(dāng)對對象執(zhí)行查找某個屬性的時候,它首先查找實例里的是否存在這個屬性,如果沒有,就在對象的”私有”原型上查找。原型可以有他們自己的私有原型,所以查詢可以沿著原型鏈繼續(xù)執(zhí)行,直到找到屬性或者當(dāng)?shù)竭_空的私有原型里,依然沒有找到。
創(chuàng)建子類
回到person對象,這個時候,我們需要添加更多的信息,讓這個person看起來像一個面試者。那么,我們這樣定義。
- KevLinDev.extend = function(subClass, baseClass) {
 - function inheritance() {}
 - inheritance.prototype = baseClass.prototype;
 - subClass.prototype = new inheritance();
 - subClasssubClass.prototype.constructor = subClass;
 - subClass.baseConstructor = baseClass;
 - subClass.superClass = baseClass.prototype;
 - }
 - function Employee(first, last, id) {
 - // initialize properties here
 - }
 - KevLinDev.extend(Employee, Person);
 
我們先創(chuàng)建了一個比較方便的函數(shù)去設(shè)置我們的繼承鏈。我們需要讓baseclass的屬性和subclass的屬性對等。(記住,當(dāng)我們調(diào)用”new”的時候,原型屬性會被拷貝到一個實例的”_proto”中,這樣就把繼承鏈連接起來)。然而,我們不能允許subClass和baseClass的原型都指向同一個對象??雌饋砣绻obaseClass添加方法,然后subClass也同時增加了這個方法,還是比較好的。
但是,如果給subClass添加方法,baseClass也會增加相應(yīng)的方法。顯然不是我們想要的處理方式。我們需要一種方式來斷開兩個原型但是又允許subClass能繼承baseClass的方法。這個時候就需要原型鏈的幫忙了。
我們先要定義一個叫“inheritance”嵌套的函數(shù)。然后,我們把他的原型指向baseClass原型。這樣,任意一個新的“inheritance”實例都有他們自己的”_proto_”,指向基類的原型。最終,我們創(chuàng)建一個“inheritance”實例,然后把它分配給subClass原型?,F(xiàn)在我們需要創(chuàng)建一個新的subClass實例,這個實例的”_proto_”將指向“inheritance”實例。“inheritance”實例的私有原型指向基類的公共原型。
這樣,baseClass原型的改變會通過繼承鏈影響到subClass 的實例。因為我們?yōu)閟ubclass的原型屬性創(chuàng)建了一個新的對象,我們可以添加到subclass的原型中而不影響基類的原型。(小豪補充:因為我們現(xiàn)在創(chuàng)建的subClass的”_proto_”是指向“inheritance”實例。如果直接 subclass.prototype= baseClass.prototype;那么給子類添加方法的同時,基類也會增加對應(yīng)的方法)
每次你創(chuàng)建一個新的對象實例,實例自身的構(gòu)造器會指向用來實例化的構(gòu)造器(<instance>. Constructor = <object> )。我會比較一個實例和一個函數(shù)的構(gòu)造器屬性去測試對象實例化的類型。調(diào)用“new inheritance() ”把subclass原型構(gòu)造器指向了將破壞我的測試的“inheritance”函數(shù)。我可以通過更新構(gòu)造器屬性,讓他指向subclass構(gòu)造器,來修復(fù)這個問題。
最終的兩行被當(dāng)作調(diào)用祖先構(gòu)造器和方法的方便屬性。在下一個部分就需要這樣的代碼了。
調(diào)用基類
我們已經(jīng)定義了一個新的subclass,但是我們依舊需要去合適地初始化。理想狀態(tài)下,我們不應(yīng)該把代碼從person里復(fù)制到subclass,employee里。我們需要需找一個好點的方式去傳遞”first”和”last”參數(shù)到Person,讓employee自己處理id參數(shù)。下面就是實現(xiàn)方法:
- function Employee(first, last, id) {
 - Employee.baseConstructor.call(this, first, last);
 - this.id = id;
 - this.add = function(){alert(“add success”)}
 - }
 - KevLinDev.extend(Employee, Person);
 
不可否認,這樣有點丑陋。然而,我們通過”call”調(diào)基類方法。這個調(diào)用了基類構(gòu)造器就像前面的”this”。剩余的參數(shù)傳遞到了調(diào)用的函數(shù)上。那么,既然這樣,基類的構(gòu)造器person將執(zhí)行在”first”和”last”上的任一處理方法。Employee構(gòu)造器將處理“id”。
再建立一個子類
我已經(jīng)發(fā)現(xiàn)已經(jīng)建造了一個oop模式去支持一級而不是兩級或者更多等級的繼承。讓我們再創(chuàng)建一個subclasses去確定我們的概念已經(jīng)合適成型。
- function Manager(first, last, id, department) {
 - Manager.baseConstructor.call(this, first, last, id);
 - this.department = department;
 - }
 - KevLinDev.extend(Manager, Employee);
 
沒其他新的東西,這個代碼看起來和我們的employee的定義差不多,也展示了繼承正在合理的工作。
原文鏈接:http://www.kevlindev.com/tutorials/javascript/inheritance/index.htm
【編輯推薦】















 
 
 

 
 
 
 