giovedì 17 gennaio 2008

Javascript: Esempi di Programmazione a Oggetti

Javascript mette a disposizione una serie di funzionalità e costrutti del linguaggio che consentono agli sviluppatori di progettare e creare applicazioni utilizzando una metodologia di programmazione orientata agli oggetti, in modo certo non identico, ma molto simile a quanto sarebbe possibile fare con linguaggi quali Java, C++ o PHP5.

Parlare qui approfonditamente degli aspetti teorici della programmazione orientata agli oggetti sarebbe lungo e non molto utile in quanto articoli sul tema ne trovate quanti volete (per esempio questo a carattere introduttivo su Wikipedia).

Credo però che sia utile dare degli esempi di codice che aiutino a capire i concetti fondamentali, non solo perché si tratta di un argomento interessante, ma anche perché può servire come introduzione ad altri argomenti di cui ho intenzione di parlare in futuro.

Codice dimostrativo di tutti gli argomenti trattati nell'articolo è disponibile sul sito (Javascript-Oggetti). Scaricato il pacchetto zip potete semplicemente decomprimerlo in una cartella di prova sul vostro sito web o webserver locale e aprire la pagina index.html.

Creare un oggetto in Javascript

Detto nel modo più semplice possibile (e rimandando per approfondimenti all'articolo sopra citato) un oggetto, dal punto di vista che ci interessa, è un'entità che possiede propri attributi o proprietà (dati) e può compiere una serie di azioni predefinite attraverso procedure (metodi) che operano sui suoi dati.

In un oggetto quindi i dati e le procedure che operano sugli stessi sono accorpati in un'entità unica.

Per chi è abituato alla programmazione ad oggetti in altri linguaggi (esempio Java o PHP) è normale considerare gli oggetti come istanze di una classe. In Javascript la situazione è un po' diversa.

Vediamo come creare un semplice oggetto di esempio, veicolo (vedi esempio 1 del codice dimostrativo)

function Veicolo(passeggeri) {
  this.velocita = 0;
  this.passeggeri = 0;
  if(passeggeri > 0) {
    this.passeggeri = passeggeri;
  }
}

var auto = new Veicolo(1);

La prima cosa interessante da notare è che per creare un oggetto siamo partiti dalla definizione di una funzione. Il compito che in altri linguaggi orientati agli oggetti è svolto dalle classi, definire cioè gli attributi e i metodi di un oggetto, in Javascript è svolto dalle funzioni.

Una funzione che viene utilizzata nel modo che abbiamo appena visto per creare un oggetto è detta costruttore.

this all'interno di un costruttore si riferisce sempre a quel particolare oggetto che stiamo creando. Quindi tutto il codice visto sopra crea un nuovo oggetto di nome auto (verrebbe da dire di classe veicolo, ma non sarebbe una terminologia corretta in Javascript) che possiede due attributi: velocità, con valore predefinito impostato a zero, e passeggeri, con valore predefinito impostato da un parametro passato alla funzione costruttore.

Modifica degli attributi di un oggetto

Ogni oggetto possiede una propria copia 'personale' dei valori degli attributi che lo caratterizzano. Nel costruttore, come si è visto, gli attributi possono essere impostati a valori predefiniti. Ma una volta creato l'oggetto i valori dei suoi attributi sono modificabili individualmente e possono assumere valori diversi da quelli di ciascuna copia (o istanza) degli altri oggetti creati dalla stessa funzione costruttore.

Questo concetto si esprime dicendo che gli oggetti, anche quando creati mediante la stessa funzione costruttore, hanno una propria identità.

Proseguendo con l'esempio, (vedi esempio 2 codice dimostrativo)

var auto2 = new Veicolo(1);
auto2.velocita = 2;

In questo modo creiamo un secondo oggetto e impostiamo il valore del suo attributo velocità.

La sintassi per accedere ad un attributo di un oggetto è, come si vede

nome_oggetto.nome_attributo

A questo punto dell'esecuzione lo stato degli oggetti è rappresentato dalla seguente tabella.

L'oggetto auto mantiene il valore degli attributi impostati nel costruttore, l'oggetto auto2 assume il nuovo valore (cioè 2) dell'attributo velocità.

Metodi di un oggetto

Oltre ad attributi un oggetto può possedere metodi. Un metodo è una funzione che opera sugli attributi di un oggetto determinandone il comportamento o le funzionalità.

Possiamo creare un metodo ed assegnarlo ad un oggetto in questo modo (vedi esempio 3 codice dimostrativo)

function carica(passeggeri) {
  if(passeggeri > 0) {
    this.passeggeri += passeggeri;
  }
}

function Veicolo(passeggeri) {
  this.velocita = 0;
  this.passeggeri = 0;
  if(passeggeri > 0) {
    this.passeggeri = passeggeri;
  }
  this.carica = carica;
}

Il metodo carica ha la funzione di imbarcare un certo numero di passaggeri sull'oggetto veicolo.

L'uso di this all'interno di un metodo è analogo a quello visto nella funzione costruttore: si riferisce cioè al particolare oggetto su cui il metodo è invocato.

Quindi la riga

this.passeggeri += passeggeri;

ha questo significato: somma al valore dell'attributo passeggeri dell'oggetto su cui questo metodo è invocato, il valore dell'argomento passeggeri passato al metodo.

La sintassi per invocare un metodo è la seguente

nome_oggetto.nome_metodo(argomenti_metodo);

Un metodo può non avere argomenti e in questo caso il nome del metodo è seguito da una coppia di parentesi vuote ()

var auto = new Veicolo(1);
auto.carica(2);

Dopo l'esecuzione del metodo il valore di auto.passeggeri sarà uguale a 3.

Anche se il codice sopra riportato funziona, non è questo il modo migliore di creare i metodi di un oggetto. Infatti abbiamo posto la funzione carica esternamente e quindi allo stesso livello del costruttore dell'oggetto Veicolo. Questo ci preclude la possibilità di creare un metodo carica per un oggetto diverso perché avremmo un conflitto tra nomi di funzione.

La soluzione consiste nell'incorporare la definizione del metodo all'interno della funzione costruttore in questo modo (vedi esempio 4 codice dimostrativo)

function Veicolo(passeggeri) {
  this.velocita = 0;
  this.passeggeri = 0;
  if(passeggeri > 0) {
    this.passeggeri = passeggeri;
  }
  this.carica = function(passeggeri) {
    if(passeggeri > 0) {
      this.passeggeri += passeggeri;
    }
  }
}

Così facendo possiamo utilizzare senza conflitti carica come nome di metodo per altri oggetti o nostre funzioni.

Questa è giusto una prima infarinatura sulla programmazione a oggetti in Javascript. Quanto detto può essere risultato banale o complicato a seconda del grado di familiarità che si ha con questi concetti. In caso di dubbi i commenti ci sono apposta. L'argomento comunque merita di essere approfondito e lo sarà molto presto.

4 commenti:

Anonimo ha detto...

Ero alla ricerca di un argomento che trattase le classi e JavaScript. Tra i numerosi (e spesso ingarbugliati) blog che ho trovato questo è senz'altro il migliore.
Pulito, coerente, lineare.

Grazie,

Alessandro

Massimo ha detto...

Grazie a te, sono contento che l'articolo ti sia stato utile.

Alessandro Rubino ha detto...

Ti dirò di più,

ho letto anche la seconda parte di questo post e la trovo perfetta. Ho già iniziato a sviluppare una piccola web application grazie ai tuoi scritti.

Con stima,

Alessandro

Massimo ha detto...

Grazie ancora. Se non hai difficoltà con testi in inglese, ti suggerisco di guardare anche gli articoli nei riferimenti in calce all'articolo che hai citato. In questo modo hai una panoramica completa sull'argomento programmazione a oggetti in Javascript.

Poi puoi magari decidere di usare un framework (io mi trovo bene con Mootools) che ti semplifica la vita, ma le basi in Javascript puro è bene averle secondo me.

Posta un commento

Nota. Solo i membri di questo blog possono postare un commento.