閱讀808 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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;//由於子類的構造函數被覆蓋,所有需要重置構造函數

下麵來看具體分解:

  1. 在子類的構造函數中Person.call(this);這就話的作用就是調用父類的構造函數。
  2. reader.prototype = new Person();把父類的一個實例對象賦給子類的prototype對象,這樣使得子類能夠擁有父類的所有屬性和方法。
  3. 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

  上一篇:go Digester:一個通用xml引擎的設計剖析
  下一篇:go QT的插件機製在程序發布時易出現的問題