javascript繼承之為什麼要繼承

來源:互聯網
上載者:User

Quiz1
Javascript真的需要類(Class)嗎?
我們首先先看下其他有類(Class)的物件導向語言(如:Java)的一些特性。

父類與子類
父類(Superclass)和子類(Subclass),並不是為瞭解決父親與兒子的問題,而是為瞭解決類的內含項目關聯性的,我們用Sub表示“子類”,用Sup表示“父類”,則有:
  Sub Sup
這是有區別的,例如通常我們能夠將子類當成父類來使用,但認人的時候我們並不能把兒子當成父親。
或者可以這麼說,父類和子類不是為瞭解決類間存在相同方法或者屬性的。

舉個例子
有人喜歡這樣做:
我們需要一些動物的類,以便在螢幕上建立一些移動的動物,但移動的動物有些在空中飛行,有些在路上行走。
所以建立兩個父類,一個是Fly,一個是Walk: 複製代碼 代碼如下:Class Fly{
Fly(){}
}
Class Walk{
Walk(){}
}

然後獅子們(還可以再建些其他的在路上行走的動物)就屬於Walk類,老鷹們(也還可以再建些其他在天上飛行的動物)就屬於Fly類: 複製代碼 代碼如下:Class Lion extend Walk{
}
Class Eagle extend Fly{
}

最後對Lion和Eagle類建立一些執行個體,調用相應的方法,螢幕上就會有一些獅子和老鷹在移動了。
但這可能並不是一個好的設計,比如明天老闆突然一拍大腦,他要有一種叫天馬(Pegasus)的動物,它們即會在天上飛,又會在路上走,時而要飛行,時候要行走。
在這種情況下,這個方案就全然無用了。

為什麼這個設計失敗了?
繼承是有條件的,子類必須能嚴格的向上轉型(變成父類)。
在上面這個例子中:
獅子(Lion)被假設等同於行走動物(Walk),老鷹(Eagle)被假設等同于飛行動物(Fly)。
這看起來很成功,因為子類能嚴格向上轉型,但他有隱患。
當有一種天馬(Pegasus)介入到裡面的時候,我們才發現獅子其實只是“會行走的動物”,老鷹其實只是“會飛行的動物”,這不意味著動物一輩子只能飛行或者行走,所以即會飛行又會行走的天馬就找不到自己的歸屬了。
這個例子很好的證明了,子類和父類不是為瞭解決類間具有相同的方法的:
一些動物都會行走,需要擁有行走(Walk)這個方法,但這不應該由子類和父類實現。

組合
我們可以這樣解決這個問題: 複製代碼 代碼如下:Class Lion{
walker = new Walk();
walk(){
return walker.walk();
}
}
Class Eagle{
flyer = new Fly();
fly(){
return flyer.fly();
}
}
Class Pegasus{
walker = new Walk();
flyer = new Fly();
walk(){
return walker.walk();
}
fly(){
return flyer.fly();
}
}

組合是簡單的在新類內部建立原有類對象。所以組合才是為瞭解決類間具有相同的方法的。在這個例子裡面:
Walk被當成“會行走的動物應該擁有的方法集合”,同理Fly被當成“會行走的動物應該擁有的方法集合”,所以對於天馬(Pegasus),我們只需要對Walk和Fly進行組合就行了。

繼承的目的
繼承並非代碼複用的唯一方法,但繼承有他的優勢:
子類可以向上轉型變成父類。
這樣我們就可以忽略所有的子類差異,當成相同的類來操作,例如:
我們有方法fn(A),fn(B),這兩個方法實際是相似的,我們想複用他們。
則我們可以通過設立一個父類C,其中A是C的子類,B是C的子類,那麼fn(C)就可以複用在A和B身上了。

回到Javascript
但回到Javascript,我們發現上面的例子是不成立的。
因為Javascript本身是弱類型語言,它並不會在操作前(因為他不用編譯)關注自己操作的物件類型是什麼。他只會執行成功,或者發生錯誤。
這時候,繼承顯得並不必要了。那麼類也就同樣不是必要的了。
I have been writing JavaScript for 8 years now, and I have never once found need to use an uber function. The super idea is fairly important in the classical pattern, but it appears to be unnecessary in the prototypal and functional patterns. I now see my early attempts to support the classical model in JavaScript as a mistake.
——Douglas Crockford
我寫Javascript代碼已經8年了,但我從來沒有發現需要使用超類函數。超類的想法在古典設計模式是非常重要的,但這在以原型和函數為基調的模式中並不必要。我現在覺得,早期我試圖讓Javascript支援傳統模式是一個錯誤的決定。

安全環境
當然,你可以手動去判斷類型,控制參數的類型,進而提供一個較為安全的環境。
例如同樣作為弱類型指令碼語言的PHP,為了類比強型別物件導向語言設定安全環境,不得不這麼做: 複製代碼 代碼如下:class ShopProductWriter{
public function write( $shopProduct ){
if( ! ( $shopProduct instanceof CdProduct ) && ! ( $shopProduct instanceof BookProduct ) ){
die( "輸入錯誤的類型" );
}
//如果類型正確就執行一些代碼
}
}

——PHP Objects, Patterns, and Practtice Third Edition . Matt Zandstra
但這隻是一個非常醜陋的方案而已。

經典繼承文法糖實現
不過經典繼承依然是許多人喜歡的方式。所以YUI、Prototype、Dojo、MooTools都提供了自己的實現方案。
其中較為常見的方案中,文法大概是這樣的: 複製代碼 代碼如下:var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
}
});
var Dancer = Person.extend({
init: function(){
this._super( true );
}
});
var n = new Dancer();
alert(n.dancing); //true

最重要的實現是對this._super的實現,其實extend函數只是將傳進來的對象重新組裝了一下,變成一個原型對象,新建構函式的prototype裡。
具體實現請查看參考文獻1。

ECMAScript 6的經典繼承文法糖
對於類庫各自實現,導致經典繼承文法眾多,ECMA組織貌似不太滿意,他們試圖在ECMAScript 6中加入更加直觀的經典繼承文法糖: 複製代碼 代碼如下:class Animal {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}
class Dog extends Animal {
constructor(name) {
super(name);
}
bark() {
console.log("Woof!");
}
}

總結
實際上,Javascript中經典繼承並不是必要的。
然而基於許多人喜歡經典繼承模型,所以在新版的ECMAScript 6中提供了相關文法糖。
不過在中國,前端想廣泛使用該文法糖應該是一個遙遠的故事……

Quiz2
那Javascript特有的繼承呢?

原型繼承
原型繼承不是解決經典繼承中的集合內含項目關聯性的,實際上原型繼承是解決從屬關係的,用數學表達就是:
  Sub.prototype ∈ Sup
子級建構函式(子類型)原型是一個父級建構函式(父類型)構建的執行個體對象。原型實際上是子類型執行個體中需要共用的東西: 複製代碼 代碼如下:function Being(){
this.living = true;
}
Being.prototype.walk = function(){
alert("I' m walking");
};
function Dancer(){
this.dancing = true;
}
Dancer.prototype = new Being();
Dancer.prototype.dance = function(){
alert("I'm dancing");
};
var one = new Dancer();
one.walk();
one.dance();

利用借用、寄生等技術可以產生很多不同的繼承效果,但這些技術都只是為瞭解決原型繼承中屬性和方法一些公用與非公用的問題罷了。由於篇幅問題就不展開討論了,有興趣可以參考《Javascript進階程式設計》相關內容。

思考題
1.文章開頭關於天馬(Pegasus)的題目,如果在Javascript上,應該如何設計呢?例如我們有下列兩個類型: 複製代碼 代碼如下:function Walk(){
this.walk = function(){
//walk
};
}
function Fly(){
this.fly = function(){
//fly
};
}

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.