Codeflyer.Com


agosto 29, 2006

Classi ed ereditarietà

Archiviato in: Javascript — Davide Fiorello @ 9:02 pm

La gestione delle classi in javascript è leggermente diversa da quella a cui siamo abituati negli altri linguaggi di programmazione. Javascript, NON è un linguaggio class-basedì bensì un linguaggio prototype-based.
I linguaggi prototype-based, a differenza di quelli class-based, non fanno distinzione fra classi e istanze.
Ciò comporta non pochi problemi nell'utilizzo e bisogna fare molta attenzione.

Definiamo una classe:

JavaScript:
  1. function Person() {
  2.    this.name = "";
  3.    this.age = 15;
  4. }
  5.  
  6. Person.prototype.setName = function(newName){
  7.   this.name = newName;
  8. }
  9.  
  10. Person.prototype.setAge = function(newAge){
  11.   this.age = newAge;
  12. }

Abbiamo definito una classe MyClass con due campi (name e age) e due metodi (setName e setAge)

Ora deriviamo la nostra classe:

JavaScript:
  1. function Male() {
  2.    this.gender = 'M';
  3. }
  4. Male.prototype = new Person();

a questo punto utilizziamola:

JavaScript:
  1. var davide = new Male();
  2. davide.setName("davide");
  3. davide.setAge(35);
  4.  
  5. alert(davide.name+" "+davide.age+" "+davide.gender);

Il risultato attteso sarà un bel pop-up contenente la string "davide 35 M";

...se aggiungiamo...

JavaScript:
  1. var marco= new Male();
  2. marco.setName("marco");
  3. marco.setAge(22);
  4.  
  5. alert(marco.name+" "+marco.age+" "+marco.gender);

il nuovo pop-up ci restituirà "marco 22 M";

E fin qua nulla di nuovo, i problemi sorgono quando nei campi ci sono degli oggetti un po' più complessi della semplice stringa e che vengono aggiornati senza utilizzare l'assegnamento.
Quando si cerca di accedere al campo "nome" dell'oggetto di tipo "davide", viene verificata innanzitutto la presenza nella classe "Male", se non viene trovata si risale alla classe Person.
Nel momento stesso in cui viene fatto l'assegnamento, tramite la setName, non viene aggiornato il valore ma viene creata una nuova proprietà nell'oggetto "davide" creato.
L'effetto è molto più chiaro se utilizziamo un array.

Aggiungiamo alla nostra classe.

JavaScript:
  1. function Person() {
  2.    this.name = "";
  3.    this.age = 15;
  4.  
  5.    this.preferredColors = new Array();
  6. }
  7.  
  8. Person.prototype.addPreferredColor = function (color) {
  9.    this.preferredColors[this.preferredColors.length] = color;
  10. }
  11.  
  12. Person.prototype.printColors = function() {
  13.    return ....Una stringa contenente la lista dei colori....
  14. }

..ed utilizziamo la nuova funzionalità

JavaScript:
  1. ...
  2.    davide.addPreferredColor('Giallo');
  3.    davide.addPreferredColor('Rosso');
  4.  
  5.    marco.addPreferredColor('Nero');
  6.  
  7.    alert(marco.printColors());

Quello che ci si aspetterebbe in output è "Nero"

invece l'output sarà "Giallo, Rosso, Nero"

Cos'è successo?
Nei due oggetti creati non era stata definita la proprietà "preferredColor" e quindi è stata utilizzata quella dell'oggetto "Person". In un linguaggio class-based non ci sarebbero stati problemi in quanto, essendo la classe separata dall'istanza, ogni oggetto avrebbe avuto il suo array. In javascript invece questa separazione non c'è e quindi la proprietò a cui accedono i due oggetti è lo stesso.

Come si risolve?
Semplice, l'inizializzazione della proprietà va fatta nelle classi derivate e non nella classe madre.

JavaScript:
  1. function Person() {
  2.    this.name = "";
  3.    this.age = 15;
  4. }
  5.  
  6. function Male() {
  7.    this.gender = 'M';
  8.    this.preferredColors = new Array();
  9. }

...mentre i metodi che lavorano con la proprietà in questione si possono tranquillamente lasciare nella classe madre.

Poco comodo, lo so, ma al momento è l'unico modo che ho trovato per farlo.

Nessun commento »

Non c’è ancora nessun commento.

RSS feed dei commenti a questo articolo. TrackBack URI

Lascia un commento

generiert in 0.862 Sekunden. | Powered by WordPress