簡體   English   中英

為什么Javascript默認不支持繼承?

[英]Why Javascript does not support inheritance by default?

從OOPS基礎開始,我總是使用繼承作為代碼重用的強大工具,

例如,如果我在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不支持經典繼承作為默認選項?

[2018年更新]現在,JavaScript顯然支持使用本機語言功能進行繼承。

class A { }
class B extends A { }

[/更新]

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();

因為Javascript不是基於類的面向對象語言 ,而是原型 語言 這只是一個設計決定。

此外,Javascript從來沒有真正“意味着”我們今天用它做的所有事情(從Node.js到ASM.js)。 它仍然相關的事實是Brendan Eich和Co.的遺囑。所以你可能想知道為什么X或Y從未在JS中實現,但事實是我們使用JS來解決20年前無法預見的問題。

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

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

那些作者傾向於給予他們的祝福而不是“接口繼承” - 但是在諸如JavaScript之類的鴨子類型語言中,沒有必要明確地聲明這樣的繼承。

在JS中,您可以通過簡單地將其作為多個對象的屬性來“重用”相同的函數。 無論你需要什么樣的遺產,你都可以從無到有。

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);

以下代碼塊將“擴展”另一個JavaScript原型,並確保“instanceof”運算符對基類和派生類正常工作。

據我所知,將TestB的原型設置為新的TestA允許“instanceof”運算符的邏輯包含。

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

這樣做是風格欲望和實用欲望之間的平衡。 這將適用於大多數瀏覽器,甚至Internet Explorer,如果你被迫支持它。 它也有幫助,因為同一塊中包含的方法“感覺”很像傳統的OO語法。

此外,JavaScript不支持傳統的面向對象風格的主要原因是它的創始理念。 創始哲學是自由。 這種自由旨在允許開發人員設計自己的樣式以滿足項目的需求。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM