LEZIONE VI - Oggetti "avanzati" di JS (parte A)
Questa lezione è dedicata alle nuove tecniche di programmazione JS: l'uso di oggetti per la creazione di funzioni generiche riutilizzabili.
Uno dei primi ad utilizzare queste tecniche di programmazione è stato
Google con la realizzazione di Gmail e altri prodotti con interfaccia dinamica. Gmail, per chi l'ha usato, utilizza al 100% AJAX per l'interazione client -> server, sfruttando funzioni generiche create dai loro programmatori, funzioni che poi vengono riutilizzate anche in altri servizi che offrono.
Dopo che Google ha realizzato Gmail, c'è stata una "gara" promossa da molte aziende per produzione di funzioni e classi GRATUITE che forniscano un aiuto per la realizzazione di programmi interattivi su interfaccia AJAX.
Una delle migliori in assoluto, e da cui molti programmatori poi hanno sviluppato utility che si interfaciano con questa libreria di funzioni, è quella realizzata da
Yahoo, denominata
YUI (Yahoo User Interface). Sarà scopo di una delle prossime lezioni spiegare e chiarire il funzionamento di questa libreria, la sua praticità, utilità e come implementarla nelle proprie applicazioni.
Tornando allo scopo di questa lezione, vediamo come funzionano queste tecniche di programmazione ad "oggetti multipli", tecniche che poi ci aiuteranno a capire meglio come funzionino anche le librerie YUI.
Questa tecnica di programmazione che io ho definito ad "oggetti multipli", ci permette di creare delle funzioni intrinseche ad un determinato. Cosa intendo per intrinseche?
Normalmente nella tecnica standard di programmazione JS una funzione è un gruppo di codice che viene richiamato:
function lamiafunzione() {
il codice della funzione
}
Questo modo di scrivere il codice e validissimo (e in molti casi basta e avanza), però ha dei difetti:
- ogni funzione è indipendente da altre funzioni
- la funzione fa riferimento solo a se stessa
- non può essere utilizzata come oggetto
La forza dei linguaggi di pogrammazione rivolti ad oggetti è proprio quella di poter gestire gli oggetti in modo pratico e veloce, oltre che ad avere in "una sola variabile" tutti gli elementi necessari a gestire la stessa.
Un esempio degli elementi base della programmazione JS rivolta ad oggetti è il comando
prototype, comando che ci permette di creare funzioni personali legate ad un determinato oggetto e di richiamare questa funzione semplicemente con una parola.
Facciamo un semplice esempio per capire questa logica. In JS non esiste per esempio una funzione utilissima che invece esiste in PHP:
nl2br() funzione che converte tutti i ritorni a capo in una stringa con il tag "<br>" per stampare la stringa in una pagina HTML.
Noi possiamo farci quest funzione in JS in due modi:
- quello classico
- utilizzando gli oggetti e prototype
Nel primo modo la funzione sarebbe:
function nl2br( testo ) {
return testo.replace(/\r?\n/g, "<br>");
}
dove per avere il testo formattato dobbiamo scrivere
var testoformattato = nl2br( testo );
Nel caso invece del prototype, la nostra funzione diventa una funzione legata ad un determinato oggetto, che nel nostro caso è l'oggetto JS
String
String.nl2br.prototype = function() {
return this.replace(/\r?\n/g, "<br>");
}
dove per avere il testo formattato dobbiamo far riferimento all'oggetto e scrivere semplicemente
var testoformattato = testo.nl2br();.
Molti diranno: non è poi che ci sia tanta differenza tra le due cose?
In effetti questo è un esempio semplicissimo, fatto appositamente per farvi vedere le due tecniche di programmazione differenti e per farvi entrare il un contesto di "oggetto". Infatti se guardate bene la funzione del prototype, non c'è alcun riferimento all nostra variabile
testo ma viene utilizzato l'elemento
this, elemento che fa riferimento all'oggetto che viene passato alla funzione.
Nell'esempio sopra abbiamo usato un oggetto esistente nella gerarchia JS (String), ma il comando prototype la possiamo agganciare anche a nostri oggetti preventivamente creati. Questa cosa la vedremo più avanti dato che non abbimo ancora inziato a costruire un oggetto proprio.
Come abbiamo letto sopra, un oggetto è "una variabile" che al suo interno può contenere variabili, array, funzioni o altri oggetti.
In JS per creare un oggetto possiamo utilizzare un suo comando bn specifico
var oggetto = new Object() oppure utilizzare un metodo più pratico e veloce:
oggetto = {}
Tutto quello racchiuso tra le due parentesi graffe fa parte del nostro oggetto. La sintassi che deve essere utilizzata deve essere
elemento : valore separando con una virgola eventuali altri elementi, quindi vedendo questa sintassi esplosa in un oggetto con più elementi vedremmo ad esempio:
oggetto = {
numero : 1,
testo : "Ciao come stai?",
funzione: function {
...la nostra funzione...
},
subogg : {elemento1:valore1, elemento2:valore2},
array : [
'pincopallo',
'tricesimo'
]
}
Se adesso volessimo richiamare un qualsiasi elemento del nostro oggetto, ad esempio il
testo, basta semplicemente richiamare la gerarchia partendo dalla nostra variabile:
oggetto.testo.
Allo stesso modo potremmo richiamare la nostra funzione
oggetto.funzione() oppure l'elemento2 del nostro sub oggetto
oggetto.subogg.elemento2. Questo se richiamimo il nostro oggetto dall'esterno di se stesso, mentre se lavoriamo all'interno dell'oggetto stesso potremmo fare riferimento utilizzando l'elemento proprietario
this. Ad esempio se il nostro
oggetto.funzione() dovesse stampare il contenuto di
oggetto.testo, la funzione sarebbe semplicemente:
funzione: function {
alert( this.testo );
},
dove
this è il nostro oggetto "padre". Visto così ancora sembra abbastanza "inutile", basta invece vederlo all'opera su qualcosa di più interessante per capirne l'utilità, tipo la creazione di oggetti personali da utilizzare in modo generico per tutte le nostre applicazioni.
Nelle lezioni precedenti abbiamo visto come viene generata una connessione AJAX utilizzando XMLHttpRequest; in particolare in un esempio (quello della chat), abbiamo realizzato 2 funzioni (una per il refresh della chat e l'altra per inserire il messaggio) e ogniuna delle funzioni utilizzava una "propria" connessione remota. Possiamo rimodificare quel codice e renderlo molto più "semplice" se la parte che riguarda la connessione diventa un oggetto a se stante richiamabile da una qualsiasi funzione.
Vediamo inanzittutto come si presenterebbe il codice modificato e dopo vedremo come poter creare il nostro oggetto "connessione".
Cerchiamo di vedere il codice convertito anch'egli in un oggetto:
myFunc.Widget.Chat = {
URL : "./chat.php",
refresh : function () {
myFunc.Utility.Connect.asyncRequest("POST", this.URL, this.resultMex, "act=messaggi");
},
aggiungi : function () {
document.getElementsByTagName('input')[0].value =
document.getElementsByTagName('input')[0].value.replace(/[^a-z0-9]/ig, '');
var utente = document.getElementsByTagName('input')[0].value.replace(/^\s/g, '').replace(/\s$/g, '');
var messaggio = document.getElementsByTagName('input')[1].value.replace(/^\s/g, '').replace(/\s$/g, '');
var param = 'act=aggiungi';
param += '&utente=' + escape(utente);
param += '&messaggio=' + escape(messaggio);
if ( utente && messaggio ) {
myFunc.Utility.Connect.asyncRequest("POST", this.URL, this.resultAdd, param);
} else {
alert("Tutti i campi sono obbligatori");
document.getElementsByTagName('input')[0].focus();
}
},
resultMex : {
success : function ( res ) {
var xml = res.responseXML;
var chat = document.getElementById('chat');
chat.innerHTML = '';
var record = xml.getElementsByTagName('record');
for ( var i = 0; i < record.length; i++ ) {
var utente = record[i].getElementsByTagName('utente')[0].firstChild.nodeValue;
var messaggio = record[i].getElementsByTagName('messaggio')[0].firstChild.nodeValue;
var dataora = record[i].getElementsByTagName('dataora')[0].firstChild.nodeValue;
var div = document.createElement('div');
div.className = 'mex';
chat.appendChild( div );
var usr = document.createElement('div');
usr.className = 'r' + (i%2) + ' sin';
usr.innerHTML = utente + '<br><span>' + dataora + '</span>';
div.appendChild( usr );
var msg = document.createElement('div');
msg.className = 'r' + (i%2) + ' des';
msg.innerHTML = messaggio;
div.appendChild( msg );
}
setTimeout("myFunc.Widget.Chat.refresh()", 10000 );
},
failure : function ( res ) {
this.errore( res );
}
},
resultAdd : {
success : function ( res ) {
document.getElementsByTagName('input')[0].value = '';
document.getElementsByTagName('input')[1].value = '';
this.refresh();
},
failure : function (res ) {
this.errore( res );
}
},
errore : function ( res ) {
alert("Errore numero "+ res.status + ": " + res.statusText);
}
}
Il codice sopra l'ho scritto ma non l'ho provato... spero non ci siano errori!!

A parte questa precisazione, ho riconvertito il codice spiegato nella
lezione numero 4 utilizzando le cose spiegate sopra.
In questo codice vi manca una parte importante, ovvero
myFunc.Utility.Connect l'oggetto che si preoccupa di creare connessioni remote multiple verso il server in modalità
asincrona e, una volta elaborati i risultati, di passarli alla funzione appropriata. Questo oggetto lo vedremo nella seconda parte di questa lezione, dove step-by-step vedremo di crearlo assieme.
Tornando all'esempio sopra, se guardate bene a parte la formattazione del codice in modalità "oggetto" le funzioni che sono contenute sono esattamente quelle del codice generale con solo alcuni accorgimenti. Lascio a voi cercare di capire cosa ho scritto e perchè è stato scritto in qual modo; se avete problemi o dubbi, avete a disposizione sempre
l'area apposita del forum per lasciare il vostro messaggio.
Vi aspetto per la
seconda parte di questa lezione!