In che modo l'eredità prototipale è praticamente diversa dall'ereditarietà classica?

27

L'ereditarietà, il polimorfismo e l'incapsulamento sono le tre caratteristiche più distinte e importanti dell'OOP, e da queste l'ereditarietà ha una statistica di utilizzo elevata al giorno d'oggi. Sto imparando JavaScript, e qui, tutti dicono che ha un'eredità prototipale, e la gente dappertutto dice che è qualcosa di molto diverso dall'ereditarietà classica.

Tuttavia, non riesco a capire qual è la loro differenza dal punto di utilizzo pratico? In altre parole, quando definite una classe base (prototipo) e ne derivate alcune sottoclassi, avete entrambi accesso ai funzionali della vostra classe base, e potete aumentare le funzioni sulle classi derivate. Se consideriamo quello che ho detto essere il risultato voluto dell'ereditarietà, allora perché dovremmo preoccuparci se usiamo la versione prototipale o classica?

Per chiarirmi di più, non vedo alcuna differenza nell'utilità e negli schemi di utilizzo dell'ereditarietà prototipale e classica. Questo mi porta a non avere interesse a capire perché sono diversi, dato che entrambi producono la stessa cosa, OOAD. Quanto praticamente (non teoricamente) l'eredità prototipale è diversa dall'ereditarietà classica?

    
posta Saeed Neamati 07.08.2011 - 20:24
fonte

4 risposte

6

Post del blog recente su JS OO

Credo che il tuo confronto sia emulazione OO classica in JavaScript e OO classico e ovviamente non vedi alcuna differenza.

Dichiarazione di non responsabilità: sostituisci tutti i riferimenti a "OO prototipo" con "OO prototipo in JavaScript". Non conosco le specifiche del Sé o di qualsiasi altra implementazione.

Tuttavia OO prototipo è diverso. Con i prototipi hai solo oggetti e puoi solo iniettare oggetti in altri prototipi di catena. Ogni volta che accedi a una proprietà su un oggetto, cerchi quell'oggetto e qualsiasi oggetto nella catena del prototipo.

Per OO prototipo non esiste la nozione di incapsulamento. L'incapsulamento è una funzionalità di scope, chiusure e funzioni di prima classe ma non ha nulla a che fare con OO prototipale. Non c'è anche nozione di ereditarietà, ciò che la gente chiama "eredità" è in realtà solo polimorfismo.

Tuttavia ha polimorfismo.

Ad esempio

var Dog = {
  walk: function() { console.log("walks"); }
}

var d = Object.create(Dog);
d.walk();

Chiaramente d ha accesso al metodo Dog.walk e questo mostra il polimorfismo.

Quindi in realtà c'è una grande differenza . Hai solo il polimorfismo.

Tuttavia, come accennato, se hai desiderato farlo (non ho idea del motivo per cui lo faresti) puoi emulare OO classico in JavaScript e avere accesso a (limitato) l'incapsulamento e l'ereditarietà.

    
risposta data 08.08.2011 - 00:11
fonte
15

L'ereditarietà classica eredita il comportamento, senza alcuno stato, dalla classe padre. Eredita il comportamento nel momento in cui l'oggetto viene istanziato.

L'ereditarietà prototipale eredita il comportamento e lo stato dall'oggetto padre. Esso eredita il comportamento e lo stato nel momento in cui viene chiamato l'oggetto. Quando l'oggetto genitore cambia in fase di esecuzione, lo stato e il comportamento degli oggetti figli sono influenzati.

Il "vantaggio" dell'ereditarietà prototipale è che è possibile "correggere" lo stato e il comportamento dopo che tutti gli oggetti sono stati istanziati. Ad esempio, nel framework Ext JS è comune caricare "overrides" che correggono i componenti principali del framework dopo che il framework è stato istanziato.

    
risposta data 08.08.2011 - 17:54
fonte
9

Primo: La maggior parte delle volte utilizzerai gli oggetti, non li definirai e l'uso degli oggetti è lo stesso in entrambi i paradigmi.

Secondo: la maggior parte degli ambienti prototipali usa lo stesso tipo di divisione degli ambienti basati sulla classe - dati mutabili sull'istanza, con metodi ereditati. Quindi c'è ancora poca differenza. (Vedi la mia risposta a questa domanda di overflow dello stack , e Self Paper Organizzazione dei programmi senza classi . Guarda Citeseer per una versione PDF .)

Terzo: la natura dinamica di Javascript ha un'influenza molto maggiore sul tipo di ereditarietà. Il fatto di poter aggiungere un nuovo metodo a tutte le istanze di un tipo assegnandolo all'oggetto di base è accurato, ma posso fare la stessa cosa in Ruby riaprendo la classe.

Quarto: le differenze pratiche sono minime, mentre il problema pratico di dimenticare di usare new è molto più grande - cioè, è molto più probabile che tu risenta di perdere un new di quello che devi essere influenzato dalla differenza tra il codice prototipale e quello classico.

Tutto ciò che è stato detto, la differenza pratica tra l'ereditarietà prototipale e classica è che le cose-che-tieni-metodi (classi) sono le stesse cose-che-tieni-dati (istanze). Ciò significa che puoi costruire le tue lezioni sono frammentarie, usando tutti gli stessi strumenti di manipolazione degli oggetti che useresti su ogni istanza. (Questo è, in effetti, come tutte le librerie di emulazione di classe lo fanno. Per un approccio non proprio simile a tutti gli altri, guarda Traits.js ). Questo è principalmente interessante se stai metaprogrammando.

    
risposta data 08.08.2011 - 21:49
fonte
0

L'ereditarietà del prototipo in JavaScript è diversa dalle classi in questi importanti modi:

I costruttori sono semplicemente funzioni che puoi chiamare senza new :

function Circle (r, x, y) { 
  //stuff here
}
Var c = new Circle();
Circle.call(c, x, y, z); //This works and you can do it over and over again.

Non ci sono variabili o metodi privati, nella migliore delle ipotesi puoi farlo:

function Circle (r, x, y) {
  var color = 'red';
  function drawCircle () {
    //some code here with x, y and r
  }
  drawCircle();
  this.setX = function (x_) {
    x = x_;
    drawCircle();
  }

}
Circle.prototype.getX = function () {
   //Can't access x!
}

Nell'esempio precedente non è possibile estendere significativamente la classe se si ricorre a metodi e variabili privati falsi e inoltre tutti i metodi pubblici dichiarati verranno ricreati ogni volta che viene creata una nuova istanza.

    
risposta data 07.08.2011 - 21:22
fonte

Leggi altre domande sui tag