2013-04-28 15 views
6

Dal OOPS base, ho sempre utilizzare l'ereditarietà come un potente strumento per il riutilizzo del codice,Perché Javascript non supporta l'ereditarietà per impostazione predefinita?

esempio, se scrivo un programma di scacchi in OOPS e quando implementare una relazione is-a come,

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. 
}; 

I potrebbe farlo con la relazione has-a in javascript, ma lo svantaggio che sto vedendo è, Devo ridefinire ogni funzione anche nella classe derivata.

Esempio: ridefinizione della getTeamColor() di nuovo in ogni torre, cavallo, pedone, re .... ecc ..

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

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

La mia domanda è, perché javascript doesnot supporta l'ereditarietà classica come opzione predefinita ?

+0

Dai un'occhiata a jOOPL (http://joopl.codeplex.com). È una libreria orientata agli oggetti al 100% di JavaScript che incanala il linguaggio per supportare l'OOP basato sulla classe. Quindi ha ereditarietà e polimorfismo (e molte altre caratteristiche). Sto per rilasciare una nuova versione in pochi giorni con ulteriori miglioramenti. –

+6

JavaScript supporta l'ereditarietà * se lo si utilizza *. Cerca "Catena prototipo JavaScript". Per quanto riguarda "Perché javascript non supporta l'ereditarietà classica come opzione predefinita?" - perché è così che è stato definito JavaScript. Perché Java non ha Tratti ma Scala? Perché Python supporta l'MI anche se Ruby no? Perché il C++ non ha Multiple Dispatch di Dylan? Perché Eiffel consente la rottura di LSP? Bene, sono * lingue diverse * e rivendicare che uno sia corretto - tramite mezzi indiretti di "classico" - è negare che un altro approccio sia (o più) valido. – user2246674

+0

Articolo completo da Mozilla Developer Network sui dettagli del modello di oggetti javascript. [LINK QUI] (https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model). Questo articolo riguarda l'ereditarietà, la gerarchia e le relazioni mentre si effettua un confronto tra Java (basato su classi) e Javascript (basato su prototipo). –

risposta

13

JavaScript non supporta l'ereditarietà su un modo prototipale. Ciò di cui hai bisogno qui non sono le classi, ma l'incapsulamento del comportamento e la capacità di scavalcare.

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

e ora:

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

> p instanceof Piece 

vero

p instanceof Pawn 

vero

p.getColor() 

"nero"

p.move() 

avviso ...

Questo è l'approccio di base e ci sono molte librerie là fuori che trasformano questo in qualcosa che è familiare per i ragazzi che vogliono classi - per così dire.

Ad esempio, con JayData è possibile scrivere il precedente in modo più Encapsulated (con il bonus di richiamo automatico costruttore in alto nella catena:

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

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

var p = new Pawn(); 
7

Perché Javascript non è un class-based object-oriented language, ma piuttosto uno prototypal. È semplicemente una decisione di progettazione.

Inoltre, Javascript non è mai stato realmente "pensato" per tutte le cose che facciamo oggi (da Node.js a ASM.js). Il fatto che sia ancora rilevante è un testamento di Brendan Eich and Co. Quindi potresti chiedertelo perché X o Y non siano mai stati implementati in JS, ma il fatto è che usiamo JS per cose che 20 anni fa sarebbero state imprevedibili.

1

Molti buoni libri su vari linguaggi OO tradizionali (inclusi Java, C# e C++) sconsigliano specificatamente di utilizzare "l'ereditarietà dell'implementazione" laddove possibile. Esempio: efficace Java di Joshua Bloch.

Il fatto strano è che, sebbene l'ereditarietà dell'implementazione sembra dare una "forma" regolare al codice, non aiuta realmente a risolvere un problema; più spesso, causa problemi a lungo termine.

Questi autori tendono a dare la loro benedizione invece di "interfaccia ereditarietà" - ma in un linguaggio dattiloscritto come JavaScript non è necessario dichiarare esplicitamente tale eredità.

E in JS è possibile "riutilizzare" la stessa funzione assegnandola semplicemente come una proprietà su più oggetti. Qualunque sia il sapore dell'eredità di cui hai bisogno, puoi evocare dal nulla.

1

JavaScript non ha nemmeno vere classi di stile OOP, sei solo in grado di simulare qualcosa di simile.

Nel tuo esempio, è possibile ottenere l'eredità facendo

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

Tuttavia, si dovrebbe in genere collegare metodi al prototipo di funzioni, piuttosto che ad ogni nuovo oggetto creato. In tal caso, è possibile simulare l'ereditarietà attraverso la creazione di una catena di prototipi, per esempio, come CoffeeScript fa:

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

questo è imho overkill (e un po 'gergo) per le attività richieste: comportamento di override lungo l'albero delle classi. –

0

Il seguente blocco di codice sarà "estendere" un prototipo JavaScript dal altri, e garantire che l'operatore "instanceof" funziona correttamente per la base e classi derivate.

da quello che posso dire, impostando il prototipo di TestB ad un nuovo TestA consente la consistenza logica dell'operatore "instanceof".

Passando questo a TestA fornisce alla nuova istanza tutte le proprietà e i metodi desiderati.

Fare in questo modo è una sorta di equilibrio tra desideri stilistici e pragmatici. Questo funzionerà nella maggior parte dei browser, anche in Internet Explorer se sei costretto a supportarlo. Aiuta anche perché avere i metodi contenuti nello stesso blocco "sembra" molto simile alla sintassi OO tradizionale.

Inoltre, la ragione principale per cui JavaScript non supporta lo stile tradizionale di OO è a causa della sua filosofia di fondazione. La filosofia fondante è la libertà. Questa libertà ha lo scopo di consentire agli sviluppatori di progettare i propri stili per soddisfare le esigenze del progetto.

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 
Problemi correlati