Il paradigma di programmazione ad oggetti in JavaScript permette di estendere le classi di oggetti mediante prototyping (un'introduzione alla programmazione OOP in JavaScript è disponibile qui).

Il prototyping di una classe consiste nell'appendere un nuovo metodo “al volo” alla classe, che sarà poi accessibile da tutte le istanze di quella classe. Lo scenario d'uso forse più interessante è il prototyping sugli oggetti impliciti di JavaScript, tra i quali ricordiamo ad esempio String, Date e Array. In tal caso l'uso del prototyping permette di aggiungere nuovi metodi agli oggetti che usiamo più spesso, snellendo il codice in modo intelligente, perché rende facile il riuso del codice anche tra progetti diversi. Vediamo un esempio nel caso dell'oggetto implicito String.

L'oggetto implicito String

String è forse l'oggetto implicito più usato in JavaScript. I metodi più utili e conosciuti dell'oggetto String sono: toLowerCase(), toUpperCase(), match(), replace() e indexOf(). Chi non li conoscesse può dare un'occhiata alla documentazione del W3C Schools, disponibile qui.  Oltre a questi metodi, l'oggetto String permette di decidere come renderizzare la stringa, in alternativa ai CSS, mediante metodi come bold(), italic(), fontcolor() ecc. L'uso di questi metodi non intende sostituire i CSS, ma può risultare utile per implementare alcuni aspetti dinamici della pagina, senza ricorrere a PHP , ASP o JSP.

L'uso combinato di questi metodi assieme al prototyping permette di ottenere risultati comodi e maneggevoli, come vedremo nel prossimo esempio.

Il metodo print

Aggiungiamo un metodo print all'oggetto implicito String. Il codice per aggiungere il metodo potrebbe essere qualcosa del genere

if (!String.prototype.print) {

String.prototype.print = function() {

document.write(this) ;

}

}

La prima riga controlla se il metodo è già stato definito: la variabile booleana String.prototype.print sarà falsa se il metodo non esiste, vera se il metodo è già stato definito. Questo controllo è opzionale, e serve solo se temiamo che il codice qui sopra possa essere eseguito più volte all'interno della stessa pagina: se invece vogliamo forzare la ri-definizione del metodo print possiamo fare a meno di questo controllo.

Notiamo la parola prototpye, che definisce l'operazione di prototyping: se vogliamo aggiungere metodi ad un altro oggetto, useremo etichette diverse da String e print, ma la keyword protoype resterà immutata. La sintassi generale è quindi

<oggetto>.prototype.<metodo>

La definizione del metodo print è del tutto identica a quella di una normale funzione JavaScript. Il nuovo metodo non farà altro che stampare la stringa nel flusso d'uscita dell'HTML durante il caricamento della pagina. Ad esempio

<head>

<script>var my_array = ["a", "b", "c"] ;</script>

</head>

<body>

<span><script>my_array[i].print();</script></span>

...

stamperà il valore dell'elemento i-esimo dell'array my_array come contenuto del tag span (assumendo di aver già eseguito il codice di prototyping visto sopra).

Mettendo assieme i metodi di styling dell'oggetto String con il nuovo metodo print possiamo ottenere scorciatoie per produrre un output dinamico in maniera molto sintetica e leggibile, ad esempio

<span><script>

my_array[i].fontcolor("green").print();

</script></span>

A questo punto è lecito farsi una domanda: qual è il vantaggio di usare il prototyping per aggiungere il metodo print piuttosto che definire una funzione print(element) che permetta di stampare qualsiasi elemento passato come argomento, e non soltanto stringhe?

Il motivo è il seguente: una funzione print(element) generica potrebbe non essere in grado di capire che tipo di oggetto viene passato in ingresso. Questo perché non tutte le stringhe JavaScript sono riconosciute come oggetti String, ma in alcuni casi sono trattate come variabili generiche.

Consideriamo ad esempio

var s_1 = "Hello Wonderful World!" ;

var s_2 = new String(s_1) ;

alert("out_1 = " + (s_1 instanceof String)) ;

alert("out_2 = " + (s_2 instanceof String)) ;

se proviamo il codice qui sopra vedremo che solamente s_2 è un'istanza della classe String: s_1 è definita senza usare il costruttore della classe, e viene trattata come variabile generica.

Conclusioni

L'uso del prototyping può essere molto utile se vogliamo aggiungere metodi specifici ad alcuni oggetti, avendo la garanzia che il metodo sia disponibile per tutte le istanze di quel tipo, e non solo per quelle create via costruttore. Si tratta di una soluzione più elegante e riusabile rispetto alle classiche funzioni JavaScript “tutto fare”, che devono riconoscere il tipo di variabile per sapere come gestirla. Nelle prossime puntate vedremo come sfruttare al meglio il prototyping per ottenere risultati molto interessanti.