venerdì, novembre 28, 2014

Signore e signori: node.js

Questo post sarà il primo di una lunga serie per scoprire node.js, una piattaforma di sviluppo basata sul linguaggio javascript.
Tutto ciò che abbiamo imparato fino ad ora è ovviamente propedeutico al suo utilizzo.

Come si recita nella home page di node.js:

Node.js è una piattaforma, costruita sul runtime scripting di Chrome, per costruire applicazioni di rete veloci e scalabili. Node.js usa un modello guidato dagli eventi, non bloccante, che lo rende leggero ed efficiente, perfetto per applicazioni real time che devono essere eseguite attraverso device distibuiti.

Al di là di un po' di fuffa da mercante, immaginate di prendere l'ambiente di esecuzione degli script di Chrome,di renderlo indipendente dal browser, di condirlo con un po' di tools di sviluppo a corredo, di renderlo open source: ecco che dopo un pò, la comunità degli smanettoni presente in rete ha cominciato a sviluppare una miriade di moduli per node.js: cioè oggetti javascript che espongono funzionalità tipicamente utili che possiamo utilizzare al volo nei nostri programmi.

Come primo passo, installiamo la piattaforma sul nostro pc, andate alla pagina di download  e scaricate e installate la distribuzione più consona al vostro pc.

Aggiungete al path di sistema la cartella in cui è presente l'interprete node (node.exe per sistemi windows), aprite una nuova shell e digitate node -v per testare l'installazione: se è andato tutto bene dovreste visualizzare un messaggio del tipo: v.0.10.28, che rappresenta la versione della piattaforma installata.

L'eseguibile node è un interprete javascript, è possibile usarlo in maniera interattiva mandandolo in esecuzione senza parametri


Vi basterà, dopo che compare il prompt '>', introdurre le istruzioni terminate con il ';' e battere <Enter> per eseguirle.

Non è ovviamente molto comodo da utilizzare, molto meglio creare un file con estensione .js (ad esempio mioProgramma,js) e darlo in pasto all'interpre con il comando node mioProgramma.js

Node.js è stato implementato seguendo il principio della modularità, un modulo di node.js è un oggetto js che sa fare molto bene uno specifico compito: i nostri programmi tipicamente utilizzano altri moduli per portare a terminie il compito che si prefiggono.

La piattaforma node.js ha una serie di moduli compresi nell'installazione, ad esempio il modulo fs serve ad interagire con il fyle system, per la lista completa degli oggetti globali (disponibili in ogni modulo) e la lista dei moduli basta dare un'occhiata alla pagina ufficiale delle api di node, sono molto ben fatte con esempi di utilizzo per ogni funzionalità a disposizione.

Ma la forza della piattaforma è data dalla possibilità di implementare moduli aggiuntivi che sono facilmente distribuibili e utilizzabili nei nostri programmi.

La piattaforma node.js comprende un applicativo per gestire i moduli installati sulla nostra macchina, l'applicazione si chiama npm che sta per node package manager, che ci permetterà di installare o rimuovere moduli aggiuntivi.

I moduli possono essere installati a livello globale e in tal modo saranno disponibili da qualsiasi programma che andremo a sviluppare, oppure possono essere installati a livello di progetto, e in tal modo saranno disponibili solo per il progetto in questione.

Per avere una lista dei moduli installati a livello globale, eseguite il comando npm -g list, vi comparirà una vista ad albero dei moduli installati con le relative dipendenze.

Per cominciare, vediamo un esempio di programma che utilizza uno dei moduli compresi nella piattaforma

 var fs = require('fs');  
 fs.readFile('readme.txt', {encoding: 'utf8'}, function(err,data) {  
   if (err) {  
    console.log('errore in lettura file');  
   }   
   else {  
     console.log(data);  
   }  
 });  
 console.log('Prima io!');  

Per utilizzare un modulo, bisogna utilizzare la funzione globale require, passando come parametro il nome del modulo che si vuole utilizzare, in questo caso il modulo fs.

Tipicamente la funzione require restituisce un oggetto che andremo a memorizzare in una variabile, in questo caso fs.

L'oggetto fs, tra i tanti metodi, ha il metodo readFile che permette di leggere il contenuto di un file, in questo caso il file readme.txt , codificato in utf8, che deve essere presente nella stessa directory di esecuzione del programma.

Notate la natura asincrona di questo metodo, il terzo parametro è la funzione di callback che verrà eseguita non appena il file è stato caricato completamente in memoria: il metodo non è bloccante.

La piattaforma include anche la versione sincrona, readFileSync, che per motivi di efficienza va chiaramente evitata, specialmente se i file da elaborare sono molto grandi.

Per eseguire questo programma

  • create un file ProgrammaLettutaFile.js e copiateci dentro il codice
  • create nella stessa cartella un file readme.txt, con codifica utf8, e scriveteci dentro ciò che vi pare
  • eseguite il programma con il comando node ProgrammaLettutaFile.js
Il programma stamperà  il contenuto del file a video: secondo voi stamperà prima contenuto del file o 'Prima io!' ?

Abbiamo appena cominciato la nostra avventura in node.js, c'è ancora tanto da imparare, lo faremo un post alla volta :).

Su github ho aggiornato gli esempi. Rimando a questo post i dettagli su come accedere a github per ottenere in locale i sorgenti.

Usate i commenti per eventuali problemi o dubbi!

Alla prox.
Ivan


mercoledì, novembre 26, 2014

Ajax in azione

Con questo post, vi mostrerò come implementare richieste asincrone ad un componente server.

Per rendere l'esempio funzionante, ho creato una piccola applicazione web che risponde ad ogni richiesta che riceve, con la lista di due libri in formato json.

La richiesta partirà in modalità asincrona da questa stessa pagina che risiede su un dominio (blogger.com)  diverso da quello su cui è installata la mia applicazione (herokuapp.com)

Per motivi di sicurezza, non sarebbe possibile fare richieste asincrone in javascript ad un dominio diverso da quello da cui proviene il frammento javascript stesso. (same-origin policy)

Per effettuare una richiesta asincrona ad un server, utilizzando javascript standard, si utilizza un codice di questo tipo, dove ho omesso, per semplicità, eventuali controlli d'errore
  
 var xmlhttp = new XMLHttpRequest();  
 xmlhttp.onreadystatechange=function() {  
   document.getElementById("contenitore").innerHTML= xmlhttp.responseText;  
 };  
 xmlhttp.open("GET","risorsa/?eventualeparametro=valore",true);  
 xmlhttp.send();  

I passi per eseguire una richiesta asincrona sono i seguenti:
  1. istanziare un oggetto con la funzione costruttore XMLHttpRequest
  2. configurare su questo oggetto la funzione di callback che sarà eseguita quando arriverà la risposta dal server
  3. configurare il tipo di richiesta, in questo caso GET, e l'indirizzo della risorsa a cui effettuare la richiesta, che deve risiedere sullo stesso server, concatenendo all'indirizzo eventuali parametri
  4. mandare, in modalità asincrona, la richiesta: la send ritorna subito, non è bloccante. 
  5. appena il server risponde, cambierà lo stato dell'oggetto XMLHttpRequest e dunque verrà eseguita la funzione di callback che, in questo caso, riempirà il nodo che ha id = 'contenitore' con la risposta che è arrivata dal server
Se provassimo ad utilizzare questo frammento di codice utilizzando l'indirizzo reale dell'applicativo che ho sviluppato (https://ajaxjsonpexample.herokuapp.com/),  non otterremmo il risultato sperato, per il noto problema della same-origin policy.

Per ovviare a questa limitazione, nel tempo sono nate una serie di veri e propri hack, il piu' utilizzato dei quali va sotto il nome di jsonp, dove p sta per padding .

In sintesi, si deve fare in modo che la risorsa server ritorni i dati effettivi in formato json, come se fossero il parametro di una funzione:

 callback([{titolo: 'Il signore degli anelli'},{titolo: 'guerra e pace'}])  

La mia applicazione, ritorna al chiamante proprio questa stringa.

Se aggiungiamo alla nostra pagina, dinamicamente, un nodo script il cui attributo src punti all'indirizzo della mia applicazione web, il run time javascript interpreterebbe la risposta del server come una istruzione da eseguire

 callback([{titolo: 'Il signore degli anelli'},{titolo: 'guerra e pace'}])  

Ci basta allora aggiungere una proprietà dal nome callback sull'oggetto globale window, di tipo funzione, che gestisca l'array di libri ricevuti come parametro.

Provate a cliccare il bottone seguente




Ho messo l'implemetazione dell'esempio (codice lato client) su github. Fate riferimento a questo post per capire come fare ad ottenerli sulla vostra macchina.

Se aprite i web tools con F12 e andate sul tab networking e poi script, e cliccate di nuovo il bottone,potrete effettivamente osservare la richiesta fatta al server esterno con la relativa risposta.



In un prossimom post vi parlerò di heroku e di come sia facile pubblicare una nostra applicazione web su questa piattaforma di hosting che supporta già ruby,php,nodejs,java,python,scala,clojure.

L'applicazione web che ho installato su heroku è scritta in java, è costituita da una semplice servlet che scrive direttamente sulla risposta la stringa json che rappresenta l'array dei due libri.

Alla prox.
Ivan

martedì, novembre 25, 2014

Programmazione asincrona e callbacks

Una analogia per capire la differenza tra programmazione sincrona e asincrona.
Normalmente gli uomini si comportano in maniera sincrona, le donne in modo asincrono :))
Quando faccio il caffè al mattino, aspetto quei 4 secondi davanti alla tazzina che si riempie.
Mia moglie, durante quei 4 secondi magari comincia a svuotare la lavastoviglie.

In java, normalmente, l'esecuzione delle istruzioni avviene in maniera sincrona, una istruzione viene eseguita non prima che la precedente abbia finito; se si vuole una sorta di parallelismo, bisogna usare i threads, con tutto il sovracarico (overhead), in termini di risorse, che ne consegue.

In javascript non esistono i threads. Tutte le nostre istruzioni vengono eseguite, sempre, in un unico thread ma esiste la possibilità di eseguire le istruzione in modalità asincrona.

Consideriamo lo scenario in cui dobbiamo effettuare una richiesta ad un server.

In modalità sincrona avremmo ad esempio

 richiesta = preparaRichiesta();  
 risposta = mandaRichiestaSincrona(richiesta);  
 visualizza(risposta);  

Se il server impiega 10 secondi a rispondere, il nostro codice è bloccato alla seconda istruzione, non si possono eseguire altre istruzioni nel frattempo.

In modalità asincrona avremmo invece, grazie alla possibilità di passare una funzione come parametro

 richiesta = preparaRichiesta();  
 mandaRichiestaAsincrona(richiesta, function(risposta) {  
   visualizza(risposta);  
 });  
 visualizza("Siamo in attesa di risposta dal server ...");  

In questo caso, la seconda istruzione è asincrona, dopo la sua esecuzione, il nostro programma continua con l'istruzione successiva: quando il server risponderà, con i suoi tempi, verrà eseguita la funzione di callback passata come argomento alla funzione asincrona.

Tecnicamente, il supporto alla programmazione asincrona è implementato, nell'interprete javascript, tramite l'utilizzo di

  • una coda di messaggi
  • un ciclo principale di gestione eventi
Tutte le istruzioni che devono essere eseguite dal nostro programma vengono inserite in una coda di messaggi che viene gestita da un ciclo principale che svuota ed esegue, in un unico thread, le istruzioni presenti nella coda.

Nel caso di una funzionalità asincrona, dipendente da un evento esterno al nostro programma, un componente del runtime di javascript aggiunge alla coda dei messaggi la funzione di callback da eseguire, con i relativi parametri, non appena l'evento si è verificato.

Le funzioni di callback non sono mai interrompibili, così come qualsiasi funzione in javascript: in questo modo non esite mai un problema di accesso ad aree di memorie condivise da thread diversi, visto che il ciclo principale viene eseguito in un unico thread.

Avrete già sentito l'acronimo AJAX: Asynchronous Javascript And Xml: è una tecnica che permette di effettuare richieste http ad un server in modalità asincrona, sfruttando il meccanismo visto sopra: quando il server risponde, viene eseguita la funzione di callback registrata con la richiesta, che, tipicamente, modifica il DOM (Document Object Model) della pagina html corrente.

Il DOM non è altro che la rappresentazione, ad albero, in memoria, del documento html.


Una sua modifica potrebbe essere, ad esempio, la creazione di una tabella con i dati restituiti dal server.

L'utente, mentre il server risponde, ha ancora la possibilità di interagire con la pagina corrente, generando eventi che possono essere gestiti dal ciclo principale in attesa della risposta del server.

E l'XML che c'entra? Storicamente era il formato scelto per rappresentare i dati scambiati tra client e server. Ora si preferisce il formato JSON e provate ad indovinare un pò il perche ...

Più in la, vedremo come implementare richieste asincrone a componenti lato server, componenti ovviamente implementati in javascript grazie alla piattaforma nodejs ;)

Alla prox.
Ivan

















lunedì, novembre 24, 2014

Grafici di ogni tipo con flotr2

Se avete la necessità di visualizzare dei grafici sulla vostra pagina, con dati che tipicamente sono generati lato server, la libreria js flotr2 è una di quelle che fa al caso vostro.

Semplice da utilizzare, permette di creare grafici di ogni tipo con poche e chiare istruzioni.

Tempo fa ho sviluppato una pagina web che mostrava su grafici di questo tipo, l'andamento dell'utilizzo della memoria e cpu di grossi server per monitorarne le prestazioni.

I dati venivano generati lato server, leggendo alcuni file csv generati giornalmente e spediti al client in formato json, così come se li aspetta flotr2.

Oggi non mi occuperò dell'integrazione con componenti lato server (ci mancano ancora un po' di strumenti) ma definirò direttamente negli script js i dati per generare i grafici.

I passi per generare i grafici sono molto semplici.
  1. Aggiungere alla vostra pagina il riferimento alla libreria flotr2.
  2. Creare un div vuoto con un identificatore univoco nella vostra pagina html
  3.  <div id="grafico"></div>  
    
  4. Invocare
  5.  Flotr.draw(container, data, options);  
    
dove
  1. Flotr è l'oggetto globale creato dalla libreria flotr2 che espone la funzione draw
  2. container: è il div in cui si vuol visualizzare il grafico, che deve avere width e height
  3. data: sono i dati espressi come array di array es: [[x0, y0], [x1,y1],[x2,y2]...];
  4. options: è un oggetto js, opzionale, per configurare al meglio le caratteristiche del grafico
I dati rappresentano dunque coppie del piano cartesiano, la singola coppia deve essere rappresentata da un array, la serie intera da un array di coppie, cioè un array di array.

Per fare un semplice esempio, tracciamo il grafico della funzione y=x*x (x al quadrato)




Pagina html minima

 <!doctype html>  
 <head>  
      <meta charset="utf-8" />  
      <title>Esempio di Utilizzo di flotr2</title>  
 </head>  
 <body>  
   <div id="container"></div>  
   <button onclick="mioPlotter.disegna('container')">Genera Grafico</button>  
   <script src="lib/flotr2.min.js"></script>  
   <script src="js/app.js"></script>  
 </body>  

codice js presente in app.js

 var mioPlotter = (function(){  
      var dati = [],  
        i,  
        disegna = function(id) {  
                     var tavola = document.getElementById(id);  
                         tavola.setAttribute("style","width:400px; height:200px;");  
                         Flotr.draw(tavola,[dati]);  
                  };  
        for (i = 0; i < 10; i++) {  
           dati.push([i,i*i]);  
        }  
        return {  
           disegna : disegna  
        }; 
 })();  

Abbiamo creato il modulo mioPlotter con una IIFE che espone il metodo disegna invocato al click del bottone.
Il metodo disegna accetta come parametro l'id della divisione in cui verrà disegnato il grafico.
I dati del grafico sono generati con il ciclo for, che aggiunge all'array delle coppie [i,i].
Vi lascio con un quesito: come fareste a stampare il grafico di y=sqr(x) ? (radice quadrata di x)

Non abbiamo usato il terzo parametro options, i cui valori di default sono elencati qui, con il relativo significato. Provate a giocare con i parametri di configurazione es:

  Flotr.draw(container, [ data ], {  
       yaxis : {  
        max : 10,  
        min : -10  
       }  
      });  

configurando in tal modo le proprietà dell'asse y: le altre proprietà, anche se non definite, mantengono i loro valori di default.

Ho aggiornato su github il progetto, fate un git pull o, se non lo avete ancora clonato, seguite le istruzioni di questo post

Alla prox
Ivan

F12: un caccia bombardiere per sviluppatori web!

In questo post voglio parlarvi degli strumenti messi a disposizione da ogni browser moderno per i programmatori web.

Qualche anno fa, era abbastanza complicato mettere a posto del codice errato scritto in javascript, tenendo anche conto che è un linguaggio interpretato che lascia molta libertà al programmatore.

Lo strumento più in voga era l'utilizzo dell' alert, disseminato in vari punti del codice, per tracciare il valore delle variabili durante l'esecuzione, nell'arduo tentativo di capire cosa non andasse; chissà quante volte ho scordato poi alcuni alert in giro in produzione.

Per fortuna oggi abbiamo a disposizione potenti strumenti per capire cosa succede durante l'esecuzione del nostro codice js: premete F12 su qualsiasi browser: et voilà!


Io uso da una vita chrome, ma più o meno le stesse funzionalità sono presenti su tutti gli altri browser presenti sul mercato: gli strumenti di sviluppo si visualizzeranno in fondo alla pagina, potete poi decidere se visualizzare a tutto schermo o aprire il tutto inn una finestra dedicata tramite i pulsanti presenti in fondo a destra.

Quando il browser esegue del codice js, tenete sempre sott'occhio il tab Console: se ci sono errori durante l'esecuzione, l'interprete js del browser visualizza su questa Console messaggi che possono aiutare a capire cosa non va.

Facciamo un esperimento: inserirò in questa stessa pagina del codice js errato, tentando di accedere a proprietà di un oggetto non definito


 <script>  
   var ivan;  
   console.log(ivan.cognome);  
 </script>  

Aprite la console con f12 -> Console e dovreste, eventualmente tra altri errori generati dal sito blogger.com, vedere il seguente messaggio: Uncaught TypeError: Cannot read property 'cognome' of undefined 

Nel vostro codice, potete sempre scrivere sulla Console utilizzando l'oggetto globale console, magari per tracciare il valore di determinati oggetti.

 <script>  
   var persona;  
      persona.nome = 'ivan';  
      persona.cognome = 'saracino';  
      console.log(persona);  
 </script>  

Sulla Console degli strumenti, dovreste visualizzare tutte le informazioni dell'oggetto persona.

Lo strumento più in utile in assoluto è il debugger js che ci permette di eseguire il nostro codice passo dopo passo, eventualmente ispezionando i valori delle varibili del nostro programma dopo ogni istruzione eseguita.

Per attivare questa funzionalità, click sul tab Sources, selezionare a sinistra la pagina che contiene i nodi <script> inline che si vogliono analizzare o i file esterni javascript collegati alla pagina.

Nella parte centrale, se selezionate la index.html del sito blogger, troverete tutto html molto complesso in cui è presente il frammento

 <script>  
   var ivan;  
   console.log(ivan.cognome);  
 </script>  

Magari utilizzate il campo di ricerca, inserendo la parola ivan, per arrivare a visualizzare il frammento di codice in questione


Nel mio caso, ho attivato un punto d'interruzione (breakpoint) in corrispondenza della linea che cerca di usare la console, ho ricaricato la pagina con ctrl+F5, l'esecuzione si interrompe prima dell'esecuzione della linea di codice inn question: avete la possibililtà, col mouse, di visualizzare i valori delle varibili: in questo caso ho evidenziato il valore undefined della variabile ivan.

Per continuare con l'esecuzione potete utilizzare i seguenti pulsanti


Il primo pulsante continua l'esecuzione fino, eventualmente, al prossimo punto d'interruzione impostato.
Il secondo pulsante esegue (step on to) l'istruzione successiva interrompendosi all'istruzione successiva: se l'istruzione successiva è una intera funzione, viene eseguita in un colpo solo.
Il terzo pulsante esegue (step in to) l'istruzione successiva interrompendosi all'istruzione successiva: se l'istruzione successiva è una intera funzione, l'esecuzione si interrompe alla prima istruzione della funzione stessa.
Il quarto pulsante esegue (step out), senza interrompersi, la funzione corrente, fino alla prima istruzione fuori dalla funzione stessa.
Il quinto pulsante disabilità tutti i punti d'interruzione impostati.
L'ultimo pulsante abilita la modalità di pausa forzata nel caso di errori.

Esiste poi la sezione watch


che vi permette di definire qualsiasi espressione da valutare durante l'esecuzione passo passo.

Alla prox.
Ivan



sabato, novembre 22, 2014

"this" questo sconosciuto

Uno dei problemi principali che un programmatore java affronta nello studiare javascript, è capire a cosa punta il benedetto reference this.

In java è semplice, ho una classe con proprietà e metodi, istanzio un oggetto di quella classe, this rappresenta l'oggetto istanziato su cui si invocano i metodi.

In javascript non è così ovvio.

Nel contesto globale, this rappresenta l'oggetto globale window


 <script>  
   var f = function() {  
          console.log(this);  
        };  
      f();  
 </script>  

In una funzione costruttore, che deve essere invocata con l'operatore new, this rappresenta l'oggetto che verrà creato e restituito al termine dell'esecuzione della funzione stessa.

 var Auto = function(colore, cilindrata) {  
           this.colore = colore;  
           this.cilindrata = cilindrata;  
          };  
   
 var ferrari = new Auto("rossa", 6000);  

Ma provate a dimenticarvi dell'operatore new, inaspettatamente this ritorna a puntare a window.

Se dichiarate un oggetto con una proprietà di tipo funzione, tale funzione viene chiamata metodo dell'oggetto e this punta all'oggetto stesso.

 var auto = {  
    colore : "rosso",  
    cilindrata: 1500,  
    motore: "spento",  
    accendi: function() {  
             this.motore = "acceso";  
           },  
    spegni: function() {  
            this.motore = "spento";  
          }  
 };  

Provate ad omettere this nei corpi delle funzioni, vi ritroverete con una nuova proprietà motore nell'oggetto globale window, senza alcun tipo di errore in fase di esecuzione.

Fin qui, tutto sommato ce la caviamo, date un'occhiata al prossimo esempio e provate a capire a cosa punta this

 var esempio = {  
     nome: "ivan",  
     metodo: function() {  
              function inner() {  
               alert(this.nome);  
              }  
             alert(this.nome);  
             inner();  
            }  
 };  

Metodo è una proprietà dell'oggetto esempio, di tipo funzione, quindi this punta all'oggetto stesso, l'alert della funzione esterna stampa "ivan".

Nella funzione metodo, è definita una funzione interna (inner function), sarebbe molto naturale credere che il this della inner function punti allo stesso oggetto esempio, ma non è così.

Le inner function non ricevono il valore this dall'outer function.

Invocando inner(), l'alert della inner function stampa "undefined", perchè this punta a window nella inner function.

Per ovviare a questo problema, sfruttando il concetto di closure, l'esempio precedente lo riscriviamo in questo modo:

 var esempio = {  
     nome: "ivan",  
     metodo: function() {  
              var that = this;  
              function inner() {  
               alert(that.nome);  
              }  
             alert(this.nome);  
             inner();  
            }  
 };  

Memorizziamo il valore this in una varibile locale that, poichè le inner function hanno accesso alle varibili locali delle outer tramite il meccanismo delle closure, questa volta anche il secondo alert stamperà, come voluto, il valore "ivan".

Spero che ora, non abbiate piu' dubbi nell'affrontare i vari this e that :)

Alla prox.
Ivan


giovedì, novembre 20, 2014

Quando la pigrizia è cosa buona e giusta

Secondo Larry Wall, autore del linguaggio Perl, una delle tre grandi virtù di un buon programmatore è la pigrizia, come ha scritto nel suo libro, Programming Perl, 2nd Edition, O'Reilly.

E' la pigrizia che spinge un programmatore a non reinventare ogni volta la ruota e a cercare soluzioni brillanti che non facciano sprecare troppe energie :)

Se siete d'accordo su quanto scritto da Larry, allora siete come me: prima di buttarvi a capofitto a scrivere codice per risolvere un problema, provate a vedere se, per caso, qualcuno non lo ha già fatto prima di voi.

Scriverò dunque una serie di post dove mostrerò come utilizzare librerie javascript esterne, librerie che ritendo utili per il lavoro quotidiano di un programmatore web.

Usare una libreria esterna significa semplicemente utilizzare un modulo che la libreria mette a disposizione nello scope global, un concetto che dovrebbe esser chiaro dai post precedenti.

Quindi noi siamo utilizzatori di un modulo scritto da altri.

Come facciamo a rendere disponibile il modulo e relative funzionalità nel nostro codice?

 <script src="modulo.js"></script>  

Basta aggiungere il riferimento al file javascript che contiene la definizione del modulo, subito dopo possiamo aggiungere il nostro file che puo' utilizzare il modulo precedente perchè caricato prima in memoria dall'interprete javascript.

 <script src="modulo.js"></script>  
 <script src="nostromodulo.js"></script>  

Anche se, storicamente, tali riferimenti venivano messi nel nodo head della pagina html, oggi si preferisce metterli prima del nodo di chiusura del body, in modo da dare l'opportunità al browser di caricare subito in memoria e visualizzare la pagina immediatamente, evitando attese specialmente se i file js sono voluminosi.

Come primo esempio di libreria esterna, voglio presentarvi toastr, per capire a cosa serva, guardate questa demo: inserite un titolo, un messaggio, giocate con qualche parametro di configurazione e otterrete dei messaggi animati e personalizzati in posizione e colore.

Se volete vederlo all'opera direttamente su questa pagina, cliccate sul bottone seguente



Carino eh? :))

Se volete vedere il complessissimo codice di questo esempio, usate git e fate un pull per aggiornate il repository che avete in locale, altrimenti, se non lo avete ancora fatto, clonate il repository come mostrato in questo post.

Se analizzate il codice, vi accorgerete che toastr dipende a sua volta da un'altra libreria che si chiama jquery, inoltre bisogna procurarsi il foglio di stile css per rendere gradevoli i messaggi.

In questo caso, poichè toastr dipende da jquery, jquery deve essere caricato prima in memoria dal browser.

Immaginate di dover implementare ex novo ciò che fa toastr .. evviva la pigrizia ;)

Alla prox
Ivan


mercoledì, novembre 19, 2014

Array ed oggetti

Gli array in Javascript sono oggetti particolari.

Come gli oggetti che abbiamo visto fino ad ora, sono una collezione di coppie proprietà valore dove il nome della proprietà è rappresentata da un intero.

Gli array si dichiarano utilizzando le parentesi quadre come in java

 // array senza elementi  
 var array_vuoto = [];  
   
 // array con 10 elementi, separati da virgola  
 // in un array ci posso mettere quel che mi pare, anche funzioni!  
 var numeri = [  
   'zero', 'uno', 'due', 'tre', 'quattro',  
   'cinque', 'sei', 'sette', 'otto', 'nove'  
 ];  
   
 array_vuoto[1] // undefined  
   
 numeri[1] // 'uno'  
   
 array_vuoto.length // 0  
   
 numeri.length // 10  

Consideriamo invece il seguente oggetto json:

 var numeri_object = {  
   '0': 'zero', '1': 'uno', '2': 'due',  
   '3': 'tre', '4': 'quattro', '5': 'cinque',  
   '6': 'sei', '7': 'sette', '8': 'otto',  
   '9': 'nove'  
 };  
   
 numeri_object[1] // uno  
   
 // eccezione, perchè "1" non è un valido identificatore per nomi di proprietà,  
 // quindi siamo obbligati ad usare la notazione ... degli array!  
 numeri_object.1  

Come si può notare, tra oggetto json e array, il risultato è lo stesso.

La differenza sostanziale:

oggetto json eredita da Object.prototype

array eredita da Array.prototype che a sua volta eredita da Object.prototype

Un array dunque, ha a disposizione una serie di metodi e proprietà che sono tipici degli array. come ad esempio la proprietà length.

Forse non ce ne siamo ancora accorti, ma Object e Array sono due funzioni, in particolare due funzioni costruttori


 var array = new Array();   
   
 // equivalente in tutto e per tutto a  
   
 var altroArray = [];  
   
   
 var oggetto = new Oggetto();  
   
 // equivalente in tutto e per tutto a  
   
 var altroOggetto = {};  
   
 // array o altroArray hanno ad es. length, ereditato da Array.prototype  
   
 //oggetto e altroOggetto non hanno la proprietà length
 // perchè ereditano da //Object.prototype  

Al contrario di altri linguaggi come java, non c'è bisogno di specificare la dimensione massima dell'array in fase di dichiarazione, gli array sono dinamici

 var mioArray = [];  
   
 mioArray.length // 0  
   
 mioArray[10] = true;  
   
 mioArray.length // 11  
 // mioArray contiene una proprietà  

E' possibile aggiungere un oggetto come ultimo elemento dell'array con l'istruzione

 var numeri = [1,2,3,4];  
   
 numeri[numeri,length] = 5;  
   
 // [1,2,3,4,5]  

In realtà, tra i metodi di Array.prototype c'è il metodo push che fa la stessa cosa


 numeri.push(6);   // [1,2,3,4,5,6]  

Vi rimando alla documentazione ufficiale per dare un'occhiata ai metodi presenti nel prototipo di ogni oggetto array con relativi esempi

Array.prototype.concat()
Array.prototype.every()
Array.prototype.filter()
Array.prototype.forEach()
Array.prototype.indexOf()
Array.prototype.join()
Array.prototype.lastIndexOf()
Array.prototype.map()
Array.prototype.pop()
Array.prototype.push()
Array.prototype.reduce()
Array.prototype.reduceRight()
Array.prototype.reverse()
Array.prototype.shift()
Array.prototype.slice()
Array.prototype.some()
Array.prototype.sort()
Array.prototype.splice()
Array.prototype.toLocaleString()
Array.prototype.toString()
Array.prototype.unshift()

Giusto per fare un esempio, molto utile il metodo map, che permette di ottenere un nuovo array applicando una funzione, passata come argomento, che trasforma ogni elemento dell'array originale secondo l'implementazione della funzione stessa

 var numeri = [1,2,3,4,5];
   
 var numeri_raddoppiati = numeri.map(function(numero) {return numero * 2;});  
   
 // numeri_raddoppiati [2,4,3,8,10]   

Notate le potenzialità offerte dal linguaggio grazie alla possibilità di passare le funzioni come argomenti.

Ovviamente è possibile iterare un array come lo si fa in java

 var numeri = [1,2,3,4,5];  
   
 var indice;  
   
 for(indice = 0; indice < numeri.length; indice++) {  
    alert('a[' + index + '] = ' + element);  
 }  

Si ottiene lo stesso risultato, più funzionale, nel seguente modo

 numeri.forEach(function(element, index, array) {  
   alert('a[' + index + '] = ' + element);  
 });  

Credo che per oggi basti :)

Alla prox.
Ivan

martedì, novembre 18, 2014

Un pò di pratica

Non c'è niente di meglio che un pò di pratica per capire i concetti esposti fino ad ora.

Per l'occasione ho creato un progetto su GitHub, dove metterò di volta in volta tutto il materiale necessario per eseguire gli esempi che proporrò.

Git è un sistema di condivisione sorgenti distribuito.

Ognuno di voi potrà installare sulla sua macchina il repository dei sorgenti eseguendo un semplice comando da una shell, a patto di installare git per il proprio sistema operativo.

Se non usate ancora git, vi consiglio di provarlo, poi non potrete farne a meno.

Scaricatelo e installatelo seguendo questo link e scegliendo il pacchetto d'installazione in base al sistema operativo utilizzato.


  • Aggiungete al path di sistema la cartella bin presente nel percorso d'installazione
  • Create una cartella vuota che conterrà tutti gli esercizi che vi proporrò.
  • Aprite una shell nuova e posizionatevi nella cartella appena creata.
  • Eseguite il comando:
    git clone https://github.com/ivansaracino/passionejavascript.git


Il comando precedente copierà nella vostra cartella la cartella passionejavascript

Quando aggiornerò il repository remoto, vi basterà invocare il comando

  • git pull

dalla cartella radice passionejavascript.

Nella cartella passionejavascript troverete la cartella modulerevealedpattern contenente la soluzione al seguente esercizio:

Creare una pagina web con due bottoni, start e stop.
Appena caricata la pagina, il bottone start è abilitato, il bottone stop è disabilitato.
Quando premete il bottone start, dovrà partire un contatore, che si aggiornerà ogni secondo; a questo punto il bottone start diventa disabilitato e il bottone stop abilitato.
Quando premete il bottone stop, il contatore si arresterà e così via.

L'esempio non è particolarmente utile ma mostra l'utilizzo del module revealed pattern,  un design pattern in javascript, che ha lo scopo di esporre sullo scope global un unico oggetto, sfruttando il concetto di closure e IIFE che abbiamo visto in questo post

Per eseguire la soluzione vi basta aprire il file index.html in un browser.

Notate come nello scope globale ci sia solo la variabile modulo  che espone le funzioni start() e stop() legate ai click dei rispettivi bottoni presenti nella pagina html.

Tutti i dettagli implementativi sono nascosti nella IIFE.

Se avete dubbi o problemi, non fate i timidi: chiedete commentando :))

Alla prox
Ivan

lunedì, novembre 17, 2014

Ereditiamo o no?

In Javascript, non esistendo le classi, non esiste l'ereditarietà tra classi.

Esiste l'ereditarietà tra oggetti: un oggetto puo' ereditare, in fase di creazione, tutte le proprietà di un altro oggetto che costituisce il prototipo (prototype) dell'oggetto appena creato.

Ogni oggetto appena creato ha dunque un collegamento con il suo prototipo, oltre alle proprie proprietà (own properties).

Di default, ogni oggetto definito con json o con new Object(), ha come prototipo l'oggetto Object.prototype, che presenta una serie di proprietà (di tipo funzioni e quindi metodi) come hasOwnProperty(prop) che ritorna true se l'oggetto su cui si invoca contiene direttamente la proprietà indicata come argomento


 var automobile = {cilindrata: 1300, colore: 'rosso'};  
   
 console.log(automobile.hasOwnProperty('colore'));  

In questo caso verrà stampato sulla console il valore true.

Per la lista completa delle proprietà di Object.prototype rimando alla Guida Ufficile Javascript:
alcune di queste proprietà non sono standard, evitate di usarle per scrivere codice che funzioni su ogni browser.

Per creare un oggetto e assegnargli direttamente un prototipo è possibile usare la funzione Object.create(prototipo)


// o1 eredita da Object.prototype  
 var o1 = {b:3, c:4};  
   
 // o2 eredita da o1  
 var o2 = Object.create(o1)  
   
 o2.a = 1;  
   
 // o2.b nasconde o1.b  
 o2.b = 2;  
   
 // stampa true  
 console.log(o2.hasOwnProperty('a'));  
   
 //false  
 console.log(o2.hasOwnProperty('c'))  
   
 // stampa 4  
 console.log(o2.c);  

Anche le funzioni possono essere ovviamente definite nel prototipo e dunque ereditate

 var o = {  
  a: 2,  
  m: function(b){  
   return this.a + 1;  
  }  
 };  
   
 console.log(o.m()); // 3  
    
 // Quando chiamiamo o.m, in questo caso, 'this' si riferisce ad o  
   
 var p = Object.create(o);  
 // p è un oggetto che eredita da o  
   
 p.a = 12; // crea una own property 'a' su p  
 console.log(p.m()); // 13  
 // quando si invoca p.m, 'this' si riferisce a p.  

Riepilogando, ecco i diversi modi di costruire gli oggetti con le rispettive catene di prototipi

 var o = {a: 1};  
   
 // L'oggetto o ha Object.prototype come suo prototipo  
 // o non ha alcuna proprietà chiamata 'hasOwnProperty'  
 // hasOwnProperty è una proprietà posseduta of Object.prototype. 
 // Dunque o eredita hasOwnProperty da Object.prototype  
 // Object.prototype ha null come suo prototipo.  
 // o ---> Object.prototype ---> null  
   
 var a = ["ciccio", "puccio", "nicolino"];  
   
 // I vettori ereditano da Array.prototype (che ha metodi come indexOf, forEach, etc.)  
 // La catena dei prototipi di a è la seguente  
 // a ---> Array.prototype ---> Object.prototype ---> null  
   
 function f(){  
  return 2;  
 }  
   
 // Le funzioni ereditano fa Function.prototype (che ha metodi come call,   
 // bind, etc.)  
 // La catena dei prototipi di f è la seguente  
 // f ---> Function.prototype ---> Object.prototype ---> null  
   
 // Se usiamo una funzione costruttore  
 function Biblioteca() {  
  this.libri = [];  
 }  
   
 Biblioteca.prototype = {  
  aggiungiLibro: function(libro){  
   this.libri.push(libro);  
  }  
 };  
   
 var b = new Biblioteca();  
 // b è un oggetto che ha proprietà 'libri'   
 // Il prototipo di b è il valore di Biblioteca.prototype dopo   
 // l'invocazione di new Biblioteca().  

Quando dunque accediamo ad una proprietà di un oggetto, se la proprietà non è presente nell'oggetto stesso, viene risalita la catena dei prototipi fino ad arrivare a Object.prototype che ha prototipo null.

E' opportuno evitare di avere catene troppo lunghe per questioni di performance.

Alla prox.
Ivan

Ma ... funzioni costruttore? senza classe? mah ...

Purtroppo esistono diversi modi per creare un oggetto.

Quello piu' comune è attraverso la notazione json (object literal)

 var automobile = { cilindrata: 1300, colore:'rosso'};  

Lo stesso oggetto possiamo costruirlo utilizzando una funzione costruttore, che non è altro che una funzione invocata tramite l'operatore new. Vi ricorda qualcosa?


 var Auto = function(cilindrata, colore) {  
   this.cilindrata = cilindrata;  
   this.colore = colore;  
 }  
 var automobile = new Auto(1300,'rosso');  

Auto è una funzione costruttore, quando invocata con l'operatore new, this punta all'oggetto che viene appena creato, a cui si agganciano dinamicamente le proprietà cilindrata e colore: anche se non è evidenziato, l'ultima istruzione di una funzione costruttore, quando invocata con il new, ritorna l'oggetto this appena creato.

Cosa succede se ci dimentichiamo di utilizzare l'operatore new?

 var Auto = function(cilindrata, colore) {  
   this.cilindrata = cilindrata;  
   this.colore = colore;  
 }  
 var automobile = Auto(1300,'rosso');  


La funzione non ritorna alcun valore, quindi automobile ha il valore undefined, eseguendo la funzione Auto(1300, 'rosso'), aggiungiamo dinamicamente le due proprietà a this che in realtà punta a window con l'effetto di riempire lo scope global con tante variabili globali!  E' buona norma utilizzare la lettera maiuscola per identificare una funzione di tipo costruttore.

E' utile evidenziare che le due modalità di creazione degli oggetti sono assolutamente equivalenti.
Il concetto di funzione costruttore è stato introdotto per rendere familiare il linguaggio javascript ai programmatori java, ma è fuorviante perchè non esiste il concetto di Classe in Javascript, esiste solo il concetto di oggetto:

 var o1 = new Object();  
 
 var o2 = {};  

Nell'esempio, o1 e o2 sono due oggetti equivalenti. Il primo è costruito con la funzione costruttore Object(), il secondo con la notazione json.

Quindi fatevi un favore, evitate di usarla, la funzione costruttore, se ne puo' fare tranquillamente a meno ;)

Alla prox
Ivan

domenica, novembre 16, 2014

Scope delle variabili e non intendo le ramazze

Non amo i neologismi esteri, quando posso preferisco usare la nostra bella lingua, ma come si fa a tradurre il termini scope?

Non sono le ramazze, ma ogni buon informatico ne capisce il significato: lo scope di una variabile definisce l'ambito di validità della variabile stessa.

In java lo scope è definito da un qualsiasi blocco di istruzioni delimitato dalla coppia di parentesi graffe.

In javascript lo scope è, o globale, o definito a livello di funzione.

Le variabili globali sono nuove proprietà dell'oggetto window e sono accessibili da qualsiasi funzione definita a qualunque livello.

Le varibili definite a livello di funzione, sono locali alla funzione stessa e non sono accessibili da altre funzioni, se non dalle funzioni interne per creare il meccanismo di closure visto nel
post precedente.

In javascript non esiste  il concetto di scope di blocco, anche se dichiariamo una variabile all'interno di un blocco delimitato dalle parentesi graffe, è come se spostassimo la dichiarazione all'inizio della prima funzione in cui la variabile è dichiarata:

 var global = 5;  
   
 var miaFunzione = function() {  
        
      b = 100;  
   
      if (global == 5) {  
             
           var local = 10;  
        
      }  
        
      console.log(local);       
 };  
 
 miaFunzione();  
 console.log(b);  

global è una variabile globale, puo' essere acceduta da miaFunzione.

La variabile b è dichiarata senza la parola chiave var, purtroppo lo si puo' fare con lo sgradevole effetto di rendere b globale, è ovviamente sconsigliato di scrivere codice del genere.

Local, nonostante dichiarata a livello del blocco if, subito dopo la dichiarazione è come se fosse spostata all'inizio della funzione: l'istruzione di scrittura sulla console fuori dal blocco stampa il valore 10, tale meccanismo si chiama hoisting.

L'ultima istruzione stampa il valore 100, la variabile b è in effetti, una variabile globale solo perchè non si è utilizzata la parola chiave var: usatela!

Ok, adesso sappiamo tutto sulle scope, usatele bene :))
Alla prox.
Ivan



sabato, novembre 15, 2014

Spaghetti o Ravioli?

Siamo ora pronti a comprendere il codice presentato nel primo post, lo riscrivo qui per comodità

  var modulo = (function() {  
                   var f1 = function() {  
               
                            },  
                       f2 = function() {  
                 
                            },  
                       f3 = function() {  
                 
                            };  
               
                       return {  
                         f1 : f1,  
                         f2 : f2,
                         f3 : f3
                       };   
                })();  
   

Cosa contiene la variabile modulo? Contiene il risultato della esecuzione immediata della funzione dichiarata a destra, tale funzione ritorna il seguente oggetto


 {  
   f1 : function() {},  
   f2 : function() {}  
 }  
   
   

e quindi window.modulo espone le uniche proprietà f1 e f2 che in questo caso sono funzioni.

Le inner function, cioe le funzioni dichiarate all'interno di un'altra funzione, hanno l'importante proprietà di poter accedere alle variabili locali e i parametri dell'outer function anche quando l'outer function ha terminato la sua esecuzione.

Questa caratteristica, chiamata closure, insieme al concetto di  IIFE: Immediate Invocation Function Expression,  acronimo pomposo per descrivere una funzione che viene invocata appena subito dopo la sua dichiarazione, permette di creare degli oggetti che espongono solo le funzioni che vogliamo, nascondendo i dettagli implementativi; ciò ci permette di modularizzare il nostro codice, passando da un codice a spaghetti a un codice a ravioli :)

Facciamo ancora un esempio:

 var biblioteca = (function(nome) {  
        
      var libri = [],  
       
           nomeBiblioteca = nome,  
          
           inserisciLibro = function(libro) {  
               libri.push(libro);  
           },  
          
           getNomeBiblioteca = function() {  
               return nomeBiblioteca;  
           },  
          
           numeroLibri = function() {  
               return libri.length;  
           };  
   
          return {  
            insert : inserisciLibro,  
            getName : getNomeBiblioteca,  
            length : numeroLibri  
          };  
   
 })('civica di milano');  


 biblioteca.insert({titolo:'guerra e pace'});
 console.log(biblioteca.getName());
 console.log(biblioteca.length());

biblioteca è un oggetto, ritornato dalla funzione che viene immediatamente eseguita, espone dunque solo i tre metodi insert, getName, e length.

La variabile locale libri non è accessibile dall'esterno, essendo una variabile locale di una funzione,

I metodi dell'oggetto ritornato, possono ancora accedere alle variabili locali della funzione esterna, anche se la funzione esterna ha già finito la sua esecuzione: notate bene che in questo caso la eseguiamo immediatamente passandole il parametro 'civica di milano'.

Le linee di codice successive, memorizzano il libro dal titolo 'guerra e pace' nell'array libri, che esiste ancora nonostante la funzione precedente ha finito la sua esecuzione, stampano sulla console rispetivamente 'civica di milano' e 1.

Spero che ora non abbiate più dubbi sul potente concetto di closure, che ci permette di definire oggetti complessi nascondendo la loro complessita a chi deve utilizzarli.

Cominciate a utilizzare le IIFE e il vostro codice passerà da un groviglio di spaghetti a dei ravioli gustabili  uno ad uno :).

Alla prox.
Ivan

venerdì, novembre 14, 2014

Json e dintorni

Prima di affrontare il concetto chiave di closure, vediamo dunque di definire correttamente quello di oggetto in javascript.

Javascript non è tipizzato, le variabili dichiarate con la parola chiave var possono contenere numeri,stringhe,booleani (true o false), null e undefined.
I numeri, le stringhe e i booleani sono a tutti gli effetti degli oggetti, visto che hanno anche loro dei metodi, anche se sono oggetti immutabili.

Un oggetto è un contenitore di proprietà, dove  le proprietà, separate dalla virgola, hanno un nome ed un valore.
Una proprietà puo essere rappresentata da qualsiasi stringa, compresa la stringa vuota.
Il valore di una proprietà può essere un qualsiasi valore eccetto undefined

Gli oggetti sono utili per contenere e organizzare i dati, gli oggetti possono contenere altri oggetti e così possono rappresentare facilmente strutture ad albero o graphi.

Il modo standard di rappresentare gli oggetti in javascript è costituito dalle parentesi graffe aperte e chiuse che circondano zero o più coppie nome/valore.

 var oggetto_vuoto = {};  
   
 var dipendente = {  
   nome: "ivan",  
   cognome:"saracino"  
 };  
   
 var volo = {  
   compagnia: "alitalia",  
   numero: 345,  
   partenza: {  
    citta: "roma",  
    orario: "14/11/2014 13:30"  
   },  
   arrivo: {  
    citta: "milano",  
    orario: "14/11/2014 15:00"     
   }  
 };  

Ultimamente si usa il formato JSON (Javascript Standard Object Notation) per lo scambio dati tra compenenti distribuiti: il formato JSON nasce proprio dal linguaggio Javascript.

Per recuperare un valore da una proprietà di un oggetto

   
 // metodo standand di navigazione oggetti  
 volo.partenza.citta // roma  
   
 // metodo alternativo che mette in luce la natura di collezione associativa 
 // di coppie nome/valore  
 dipendente["nome"] // ivan  
   
 //proprieta noon presenti su oggetto  
 dipendente.nonesisto // undefuned  
   
 //tentativo di accedere a proprietà di proprietà inesistenti  
 dipendente.nonesisto.proprieta // eccezione a run time  

Per scrivere le proprietà di un oggetto

 // aggiornamento di una proprietà esistente  
 dipendente.nome = "ciccio";  
   
 // se una proprietà non esiste, viene creata  
 // dinamicamente!  
 dipendente.età = 43  

Le variabili che contengono gli oggetti sono dei puntatori agli oggetti in memoria.

Quando passiamo un oggetto come parametro, il passaggio del parametro è per copia  ( qui sono in disaccordo col buon Douglas Crockford che dice che il passaggio è by reference) come dimostrato dal seguente frammento di codice:

 var x = {p : 1};  
   
 var y = x;  
   
 y.p = 2;  
   
 x.p vale 2, stiamo modificando lo stesso oggetto   
 tramite lo stesso puntatore  
   
   
 definiamo una funzione che modifica la proprietà  
 di un parametro  
   
 var f = function(par) {par.p = 3};  
   
 invochiamo la funzione passando l'oggetto x  
   
 f(x);  
   
 x.p vale 3, nella funzione usiamo la copia   
 del puntatore x per modificare lo stesso oggetto in memoria  
   
 cerchiamo di cambiare l'oggetto puntato da par  
   
 var f = function(par) {par = {p:4}};  
   
 invochiamo nuovamente la funzione passando l'oggetto x  
   
 f(x);  
   
 x.p vale ancora 3, par è una copia del puntatore x,   
 copia che muore quando finisce la funzione f,  
 x punta all'oggetto originale  

In effetti il passaggio dei parametri è identico al linguaggio Java.

Ci sono altre considerazioni da fare sugli oggetti, ma credo sia opportuno dedicarci un post apposito.

Alla prox.
Ivan

E finalmente trovai gli oggetti

Nel primo post abbiamo visto come creare un modulo javascript rappresentato dalla variabile globale modulo che altro non è che un oggetto che espone le funzioni f1, f1, f3.

Qual è il vantaggio?

Invece di avere 3,4,5, ...N oggetti globali ne abbiamo uno solo e non si rischia, col tempo, di avere collisioni tra i nomi delle funzioni  (succede più spesso di quanto non si creda) generando errori difficili da risolvere.

Se avete letto con attenzione, dovrebbe risultare chiaro che, in javascript, le funzioni sono oggetti: possono essere memorizzate in varibile e possono essere passate come argomenti di altri funzioni.

Quando il browser carica una pagina html e incontra un nodo <script></script>, esegue immediatamente il codice presente in esso, il contesto di esecuzione dell'interprete javascript presenta un oggetto globale window  a cui vengono aggiunte dinamicamente le varie variabili definite nel nostro codice.

Riprendendo l'esempio del  primo post , l'oggetto window, dopo l'esecuzione della prima versione dell'esempio, presenta le nuove proprietà f1, f2,f3 il cui valori sono oggetti di tipo funzione.

Per provare l'affermazione precedente basta aprire una console javascript (F12 su qualsiasi browser moderno) e digitare window.f1, window.f2 o window.f3: la console mostrerà il valore delle tre proprietà f1,f2,f3 di window

Ecco il risultato prodotto dalla console:


Ovviamente per eseguire le funzioni, scriveremmo window.f1(); window.f2(); o window.f3(); oppure f1(); f2(); o f3() oppure this.f1(); this.f2(); this.f3(); il che significa che this = window nel contesto globale di esecuzione.

Nel secondo esempio,invece, verrà creata una unica proprietà window.modulo che questa volta è un oggetto che espone le tre funzioni per eseguire le quali scriveremo window.modulo.f1(); window.modulo.f2(); o window.modulo.f3();

Non ci stupirà allora che:

 var f1 = function() {  
                alert('f1');  
      };  
   
 Equivalente in tutto e per tutto a   
   
 function f1() {  
      alert('f1');  
 }  

La prima dichiarazione mette in risalto il concetto che le funzioni sono oggetti.

Avevo gli oggetti che cercavo sotto gli occhi e non lo sapevo :))

Alla prox.
Ivan


giovedì, novembre 13, 2014

All'inizio fu il caos ...

Non so quale sia stato il vostro primo approccio con il linguaggio javascript, io ho cominciato ad usarlo mettendo mano ad una vecchia applicazione web scritta in asp con un po' di controlli di validazione di un form.

Tanto per rendere l'idea:
 <html>  
      <head>  
           <script>  
                function f1() {  
   
                } 
   
                function f2() {  
   
                }
   
                function f3() {  
   
                } 
           </script>  
      </head>  
      <body>  
        <!-- eventi sul dom che scatenano le varie funzioni -->  
      </body>  
 </html>  
Nel mio caso le funzioni erano "solo" una ventina e già  faticavo a seguire il flusso di esecuzione del codice, impiegavo tanto tempo a fare le modifiche piu' banali.

Capite che non ci misi molto ad odiare javascript, soprattutto perchè abituato al rigore di un linguaggio ad oggetti tipizzato e compilato come Java.

Mi sentivo spaesato. Io che cercavo sempre di strutturare il codice in Java cercando di evitare codice a spaghetti, non sopportavo l'accozzaglia di funzioni e variabili globali sparse nella varie pagine html senza un minimo di struttura e di incapsulamento dei dati.

Insomma evitavo lavori di front end come la peste, ma con l'avvento del web2 e 3 e 4, a (proposito : a che punto siamo?) non potevo più nascondermi: dovevo prendere di petto il linguaggio e domarlo.

Avevo letto da qualche parte che Javascript  era comunque un linguaggio ad oggetti, ma io gli oggetti non li vedevo! Ma come si fa ad avere un oggetto senza una classe? Queste erano le mie perplessità, finchè, cercando sul web, non mi sono imbattuto in lui: Douglas Crockford e ho cominciato a scoprire le meraviglie del linguaggio.

Grazie a Douglas, l'esempio in alto ho cominciato a scriverlo così:
  var modulo = (function() {  
                   var f1 = function() {  
               
                            },  
                       f2 = function() {  
                 
                            },  
                       f3 = function() {  
                 
                            };  
               
                       return {  
                         f1 : f1,  
                         f2 : f2,
                         f3 : f3
                       };   
                })();  
   
ottenendo una unica variabile globale che incapsula le funzionalità del modulo, nascoste all'esterno come se fossero private :))

Per capire a fondo il precedente codice, bisogna padroneggiare i concetti di closure, IIFE, inner function che cercherò di illustrare nei prossimi post :))
Alla prox
Ivan