2013-04-28 97 views
6

如從OOPS基,我總是使用繼承作爲代碼重用的有力工具,爲什麼Javascript默認不支持繼承?

實施例,如果我寫在OOPS棋程序,當我實施is-a關係爲,

Class Piece{ 
    int teamColor; 
    bool isLive; 
    Positon pos; 
    int Points; 
    ....... 
    int getTeamColor(){....} 
    ....... 
}; 

Class Rook extend Piece{ //`is-a` 
...... // No getTeamColor() definition here.. because the parent has the definition. 
}; 

Class Pawn extend Piece{ //`is-a` 
......// No getTeamColor() definition here.. because the parent has the definition. 
}; 

我可以在JavaScript中使用has-a關係,但我看到的缺點是, 我必須重新定義派生類中的每個函數。

例:getTeamColor的重新定義(在每一個車,馬,卒,王再)......等。

 var Pawn = function(teamColor,pos){ 
    var piece = new Piece(teamColor,pos); 
    ....... 

    this.getTeamColor = function(){   
      return piece.getTeamColor(); 
    }; 
    } 

我的問題是,爲什麼 多年平均值的JavaScript支持經典的繼承作爲默認選項?

+0

看看jOOPL(http://joopl.codeplex.com)。它是一個100%JavaScript面向對象的庫,它增強了支持基於類的OOP的語言。因此,它具有繼承性和多態性(以及更多的功能)。我即將在幾天內發佈新版本並進行更多改進。 – 2013-04-28 08:36:02

+6

JavaScript支持繼承*,如果你使用它*。查找「JavaScript原型鏈」。至於「爲什麼JavaScript不支持經典繼承作爲默認選項?」 - 因爲這就是JavaScript的定義。爲什麼Java沒有Traits但是Scala呢?爲什麼Python支持MI,儘管Ruby不支持?爲什麼C++沒有Dylan的Multiple Dispatch呢?爲什麼埃菲爾允許LSP的斷開?那麼,他們是*不同的語言*並聲稱一個是適當的 - 通過間接手段的「經典」 - 是否認另一種方法是(或更多)是有效的。 – user2246674 2013-04-28 08:37:25

+0

來自Mozilla開發者網絡的關於javascript對象模型細節的全文。 [鏈接到這裏](https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model)。本文介紹繼承,層次和關係,同時在Java(基於類)和Javascript(基於原型)之間進行比較。 – 2013-04-28 09:08:49

回答

13

JavaScript確實支持以原型方式繼承。你需要的不是類,而是行爲的封裝和覆蓋的能力。

function Piece() { } 

Piece.prototype.color = "white"; 
Piece.prototype.getColor = function() { return this.color } 
Piece.prototype.move = function() { throw "pure function" }; 

function Pawn() { } 
Pawn.prototype = new Piece();  
Pawn.prototype.move = function() { alert("moved"); } 

現在:

var p = new Pawn(); p.color = "black"; 

> p instanceof Piece 

真正

p instanceof Pawn 

真正

p.getColor() 

「黑」

p.move() 

警報...

這是基本的做法,有許多圖書館,在那裏,把它變成的東西,熟悉了希望班的傢伙 - 這麼說。

例如與JayData可以寫以前在多個封裝方式(自動構造函數調用的獎金鍊:

var Piece = $data.Base.extend("Piece", { 
    move: function() { throw "pure class" } 
}); 

var Pawn = Piece.extend("Pawn", { 
    move: function() { ... } 
}); 

var p = new Pawn(); 
7

因爲Javascript不是class-based object-oriented language,而是一個prototypal之一。這只是一個設計決定。另外,對於我們今天所做的所有事情(從Node.js到ASM.js),Javascript從來都不是「真正意義上的」。它仍然相關的事實是Brendan Eich和Co.的遺囑。所以你可能想知道爲什麼X或Y從未在JS中實現過,但事實是,我們使用JS來處理20年前不可預見的事情。

1

許多關於各種傳統面嚮對象語言(包括Java,C#和C++)的好書特別建議不要在可能的情況下使用「實現繼承」。示例:Joshua Bloch的有效Java。

奇怪的事實是,雖然實現繼承似乎給您的代碼定期「形狀」,但它並不真正幫助您解決問題;更常見的是,它從長遠來看會導致問題。

這些作者傾向於將他們的祝福改爲「接口繼承」 - 但是在鴨子類型的語言如JavaScript中,不需要顯式聲明這種繼承。

而在JS中,您可以通過簡單地將它指定爲多個對象上的屬性來「重用」相同的功能。無論你需要什麼樣的繼承風格,你都可以從無到有。

1

JavaScript甚至沒有真正的OOP風格的類,你只是能夠模擬類似的東西。

在你的榜樣,你可以通過做

var Pawn = function(teamColor, pos) { 
    Piece.call(this, teamColor, pos); 
} 

但是,你通常應該重視方法的功能原型,而不是任何新創建的對象實現繼承。在這種情況下,您可以通過設置原型鏈來模擬繼承,例如,像CoffeeScript那樣:

var a, b, _ref, 
    __hasProp = {}.hasOwnProperty, 
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; 

a = (function() { 
    function a() {} 

    return a; 

})(); 

b = (function(_super) { 
    __extends(b, _super); 

    function b() { 
    _ref = b.__super__.constructor.apply(this, arguments); 
    return _ref; 
    } 

    return b; 

})(a); 
+4

對於所需的任務,這是imho矯枉過正(並且有點亂碼):重寫類樹下的行爲。 – 2013-04-28 08:48:43

0

下面的代碼塊將從「擴展」一個JavaScript的原型其他,並確保「的instanceof」操作符可以正常工作爲基礎,並派生類。

從我可以告訴,TESTB的原型設置爲一個新的種皮允許「的instanceof」操作符的邏輯相合。

將此傳遞給TestA爲新實例提供了所有所需的屬性和方法。

這樣做是文體慾望和實用慾望之間的一種平衡。如果你不得不支持它,這將適用於大多數瀏覽器,甚至Internet Explorer。它也有幫助,因爲使同一塊中包含的方法「感覺」很像您的傳統OO語法。

此外,JavaScript不支持傳統風格的OO的主要原因是因爲其創立理念。創立哲學是自由。這種自由旨在讓開發人員設計自己的風格以適應項目的需求。

function TestA(){ 
    var me = this; 

    me.method = function(){ 
    } 
} 

function TestB(){ 
    TestA.call(this); 
    var me = this; 

    me.otherMethod = function(){ 
    } 
} 
TestB.prototype = new TestA(); 

var test = new TestB(); 

console.log(test); 

console.log(test instanceof TestB); 
console.log(test instanceof TestA); 

//TestA { method: [Function], otherMethod: [Function] } 
//true 
//true