[英]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();
許多關於各種傳統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.