javascript 類式繼承與原型繼承
JavaScript類式繼承
為了更好的了解JavaScript中類式繼承的原理,我們先看一個簡單的例子。 //Super class function Person(){ this.name='張勝利'; this.age=23; this.getName = function(){ return this.name; }; }; Person.prototype.getAge = function(){ return this.age; }; //sub class function reader(){ Person.call(this); }; //這句話一定要放到添加的新方法的最前麵,否則會把新添加的方法給覆蓋掉。 reader.prototype = new Person(); reader.prototype.constructor = reader;//由於子類的構造函數被覆蓋,所有需要重置構造函數
下麵來看具體分解:
- 在子類的構造函數中Person.call(this);這就話的作用就是調用父類的構造函數。
- reader.prototype = new Person();把父類的一個實例對象賦給子類的prototype對象,這樣使得子類能夠擁有父類的所有屬性和方法。
- reader.prototype.constructor=reader;由於子類的構造函數被覆蓋,所以需要重置構造函數。
如果使用這種方法聲明一個子類,複雜又囉嗦。為了使得聲明一個子類變得簡單,我們把上麵的三步放到一個方法中,如下所示:
function extend(sub,sup){ /* *我們在此使用一個空函數,並將用它創建的一個對象實例插入到原型鏈中,這樣做 *可以避免創建超類的新實例,因為1.超類的示例可能會比較大2.超類的構造函數有一些副作用3.或者執行一些需要大量計算的任務 */ var f=function(){}; f.prototype = sup.prototype; sub.prototype = new f(); sub.prototype.constructor = sub; };
具體說明都在注釋中,不再詳解。
那麼下麵我們來看,剛開始的例子中子類如何聲明:
function reader(){ Person.call(this); }; //這句話一定要放到添加的新方法的最前麵,否則會把新添加的方法給覆蓋掉。 extend(reader,Person);
ok,現在是不是已經簡單很多了,但是我們還發現一個問題,在子類的聲明中耦合了父類的類名,為了解耦,下麵我們來看看extend方法的一個版本:
function extend(sub,sup){ var f = function(){}; f.prototype = sup.prototype; sub.prototype = new f(); sub.prototype.constructor = sub; sub.superclass = sup.prototype;//為子類添加一個superclass屬性,然後把sup的prototype對象賦予該屬性 //確保sup的prototype的constructor屬性被正確設置,這在用這個新的superclass屬性條用超類的構造函數時很重要 if(sup.prototype.constructor == Object.prototype.constructor) sup.prototype.constructor = sup; }
下麵我們來看看這個這樣使用該方法,子類是如何聲明的:
function reader(){ reader.superclass.constructor.call(this); }; //這句話一定要放到添加的新方法的最前麵,否則會把新添加的方法給覆蓋掉。 extend(reader,Person);
ok,上麵就是類式繼承的整個過程,是不是很簡單?下麵來看原型繼承:
JavaScript 原型繼承
在使用原型式繼承時,最好忘掉關於類和實例的一切知識。用基於類的辦法創建對象包括兩個步驟
1.用一個類的聲明定義對象的結構。
2.實例化該類為創建一個新對象。用這種方式創建的對象都有一套該類的所有示例屬性的副本,每一個示例方法都隻存在一 份,但每一個對象都有一個指向它的鏈接。
使用原型繼承時,不需要使用類來定義對象的結構,隻需直接創建一個字麵對象即可。這個對象隨後可以被新的對象重用,這得益於原型鏈查找的工作機製。
為了能夠更清楚的明白這個原理:
我們也先來看一個例子:
var Person = { defaultName : 'zhangshengli', getName : function(){ return this.defaultName; } }; var Reader = create(Person); alert(Reader.defaultName);
我們看到在上麵的例子中,我們用到了一個create函數,通過使用這個create函數,就會生成父類的一個子類,那麼這個子類是如何實現的呢???請看下麵:
function create(o) { function F() {};// 首先創建一個新的空函數 F.prototype = o;//把F的prototype屬性設置為傳入的參數o的原型對象,由此可以體會到JavaScript的最初設計者的意圖,prototype屬性就是用來指向原型對象的, return new F();//最後把new元素符作用於F創建的一個新對象,然後把這個新對象作為返回值返回,函數的所返回的這個克隆結果,是一個以給定對象為原型對象的空對象。 }
該函數的具體解釋,已經在注釋中,下麵我們來看看該函數的兩個變體:
/* 作為Object的prototyped的一個屬性被創建,這樣任何對象都可以使用他*/ Object.prototype.create= function () { function F() {} F.prototype = this; return new F(); }; newObject = oldObject.create();
下麵是另一個變體:
if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } newObject = Object.create(oldObject);
具體不再解釋,想必大家肯定都已經明白了,如果不太明白,在好好看看那本犀牛書。
上麵的文章如果有不妥之處,希望大家多多執政。
最後更新:2017-04-02 00:06:42