Javascript中3種實現繼承的方法和代碼執行個體,javascript執行個體

來源:互聯網
上載者:User

Javascript中3種實現繼承的方法和代碼執行個體,javascript執行個體

繼承是我們在實現物件導向編程的時候很重要的一個手段。雖然我們講不能過度繼承,多利用組合代替繼承,但是繼承總是免不了的。這裡要討論的就是Javascript中的繼承機制。

Javascript中實際上是沒有繼承的概念的,但是我們可以通過一些手段來模仿實現它。這種繼承實際上把一個對象複製到另外一個對象內部。你需要注意的是所有的本地類和宿主類是不能作為基類被繼承的,主要是為了安全方面的考慮。

Javascript中的繼承大約有三類:1.對象冒充;2.原型繼承;3.二者的混合。

一、對象冒充

其實對象冒充是跟this關鍵字緊密聯絡在一起的(所以說充分理解Javascript中的this關鍵字是多麼的重要:P)。建構函式使用this來給屬性和方法賦值,而建構函式也可以看作為一個普通的函數,所以我們就可以使我們的基類的建構函式成為子類的建構函式,然後在子類的內部調用這個函數,那麼子類就會得到父類的屬性和方法。

原理很簡單,那我們怎麼實現呢?下面就以程式碼範例,實際的操作一下。

對象冒充實現方法一,我們最常用的建立對象的方法:

複製代碼 代碼如下:
var classA = function(name){
 this.name = name;
 this.alertName = function(){
  alert(this.name);
 }
}
 
var classB = function(name,age){
 this.myConstructor = classA;
 this.myConstructor(name);
 delete this.myConstructor;
 
 this.age = age;
 this.alertAge = function(){
  alert(this.age);
 }
}

為了驗證以上的方法是否正確,你可以親自測試下,我將測試用的代碼寫在下面:

複製代碼 代碼如下:
var objA = new classA('DK');
objA.alertName();//DK
 
var objB = new classB('DS',20);
 
objB.alertName();//DS
objB.alertAge();//20

這就是所謂的對象冒充了,另外對象冒充還有另外兩種實現的方式,雖然它們的實現手段不一樣,但是它們的原理是一樣的。

對象冒充實現方法二,使用call方法:

複製代碼 代碼如下:
var classA = function(name){
 this.name = name;
 this.alertName = function(){
  alert(this.name);
 }
}
 
var classB = function(name,age){
 classA.call(this,name);
 
 this.age = age;
 this.alertAge = function(){
  alert(this.age);
 }
}

通過代碼也能看出來,第一種方法中我們建立了函數指標指向父類,調用函數,然後將指標刪除。而這裡我們之間用call方法在this對象下面運行父類的建構函式,實現了同樣的目的。另外與call方法相對於的則就是apply方法啦。

對象冒充實現方法三,使用apply方法:
複製代碼 代碼如下:
var classA = function(name){
 this.name = name;
 this.alertName = function(){
  alert(this.name);
 }
}
 
var classB = function(name,age){
 classA.apply(this,new Array(name));
 
 this.age = age;
 this.alertAge = function(){
  alert(this.age);
 }
}

其實大家可以看到,apply方法跟call方法是非常類似的,只不過傳遞參數是略有不同罷了。

二、原型繼承

大家應該對prototype對象有所瞭解,原型對象上的所有屬性和方法將被傳遞給類的所有執行個體,所有當我們把父類的所有屬性和方法付給子類的prototype對象時也就相當於實現了我們的繼承。

子類想獲得父類的所有屬性和方法,那我們將父類的一個執行個體直接付給子類的prototype對象,那我們的子類不就相當於擷取了父類的所有對象和方法?

程式碼範例伺候:
複製代碼 代碼如下:
var classA = function(){
 this.name = 'DK';
 this.alertName = function(){
  alert(this.name);
 }
}
 
var classB = function(name,age){
 this.name = name;
 this.age = age;
}
 
classB.prototype = new classA();
 
classB.prototype.alertAge = function(){
 alert(this.age);
}

注意這裡的父類的建構函式需要確保沒有參數。因為即使有構造參數在實現原型繼承的時候你也無法傳遞=.=!

三、混合繼承

顧名思義,混合繼承就是前兩種方式的混合使用了。
複製代碼 代碼如下:
var classA = function(name){
 this.name = name;
}
 
classA.prototype.alertName = function(){
 alert(this.name);
}
 
var classB = function(name,age){
 classA.call(this,name);
 this.age = age;
}
 
classB.prototype = new classA();
 
classB.prototype.alertAge = function(){
 alert(this.age);
}

使用對象冒充實現了向父類傳遞參數,同時使用原型繼承實現了對公有方法的繼承。

說完了這三中繼承方式了,下面該說到問題的時候了。

你可能會不解,為什麼有了對象冒充,有了原型繼承還要再弄出個什麼混合繼承,對,最重要的也就是這個問題。

1.如果你實際測試一下,你會發現通過對象冒充的方式實現的繼承,子類是無法訪問到父類的原型鏈上的方法的。

2.而用原型繼承,則會把所有的屬性變成共用的屬性,如果你同一個子類實現兩個執行個體,你會發現你的所有執行個體共用所有的屬性。

3.但是這肯定是不合適的了。所以就有了混合繼承的方式,讓屬性繼續保持私人,同時讓子類能夠訪問父類的原型鏈的方法。

你可以親自動手試一下,在對象冒充繼承的時候,子類無法訪問父類的原型鏈方法,原型鏈繼承子類的所有執行個體共用所有父類屬性。這裡我就不寫例子了。


[javascript練習]子類繼承父類方法並延時執行個體化

在firefox中可以用Console調試 (Ctrl+Shift+K):
console.log( var1, var2, var3 ...)在Web Console 中會顯示var1 var2 var3 ...,以一個空格隔開。

正如wjsl所說,定時器中
setTimeout(Student_A.wakeup,3000 )這裡是把Student_A.wakeup這個函數作為參數傳入了setTimeout函數。我們知道,函數的定義裡面如果有this這個reserved word,那麼它的含義取決於調用的方式。如果是用obj.function1 這種帶點的格式來調用,那麼this就是obj。 如果是直接調用,this則是window。那麼在這裡3秒鐘過後, wakeup將會被直接調用,因為您並沒有傳入Student_A。

解決辦法:加入一個sleep() 方法:
People.prototype = {      //...sleep: function(duration) { //5 秒後wakeupvar $this = this;setTimeout(function(){$this.wakeup();}, duration); },//...其中$this變數以當前對象賦值。由於js closure的特性,當setTimeout時間到,匿名函數中的$this還是之前賦予的那個對象。所以如果運行Student_A.sleep(5000),5秒鐘之後js engine 就會運行Student_A.wakeup()。
(符號“$" 跟a-z,1-9 一樣,都是變數名中可以使用的字元)。

這裡刪掉:
//Student子類建構函式,內部調用超類建構函式function Student(name) {
  People.call(this, name); //從People類繼承,同時傳遞參數name};
Java建構函式才是分開來寫的,javascript 中由建構函式產生對象(配合 new關鍵字),並沒有類。
代碼供參考:
var Student = function(classroom, name, age) { this.classroom = classroom;People.call(this, name, age);};
“醒來”之後,屬性改變:
可以先sleep(),然後馬上改屬性。然後wakeup()的時候就會發現屬性產生了變化 :D

文中的 Student.prototype 在運行 Student.prototype = new People(); 語句時被完全更改。所以setClass() 已經無法調用。可以在重寫wakeup時同樣定義。

 
在Javascript中怎實現繼承

javascript不是類,嚴格的說,沒有真正的繼承
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.