Use the left/right arrow keys to navigate, 's' to enable/disable scrolling.

Javascript

Obiettivi della lezione

Conoscere

  • conoscere le peculiarità di Javascript
  • conoscere le origini e le influenze di Javascript
  • conoscere i paradigmi di programmazione supportati e le regole di sintassi base
  • conoscere la differenze tra Javascript ed ECMAScript
  • conoscere i problemi e le potenzialità di Javascript
  • conoscere le diverse implementazioni

Sapere

  • saper scrivere un semplice programma in Javascript
  • saper utilizzare l’interprete interattivo
  • saper utilizzare i tipi di dato fondamentali
  • saper utilizzare le strutture di controllo
  • saper utilizzare le closure e le funzioni anonime

Javascript: l’altra dimensione del web

Javascript è un linguaggio di programmazione che porta il web in una nuova dimensione: la dimensione dell’interattività, della dinamicità e degli effetti speciali. Vale la pena conoscerlo, vero?

Effetti speciali per tutti!

Gli effetti speciali, le animazioni e il gioco che avete ammirato nella slide precedente

  • utilizzano esclusivamente una combinazione di HTML, CSS, SVG e Javascript
  • rispettano i principi dell’open web
  • possono essere visualizzati da qualunque browser conforme agli standard
  • non necessitano la presenza Flash

Java? No, Javascript!

Javascript è

  • Un linguaggio di programmazione

    • di alto livello
    • interpretato
    • debolmente tipizzato
    • dinamico
    • orientato agli oggetti

Javascript non è:

  • Java

Linguaggi di “alto livello”

Sono linguaggi la cui costruzione sintattica è molto più vicina a quella del linguaggio umano piuttosto che a quella della macchina.

1alert("Indovinate cosa fa questo programma Javascript!");

Linguaggi interpretati e linguaggi compilati

  • Un programma scritto in un linguaggio interpretato viene eseguito linea per linea.
  • Un programma scritto in un linguaggio compilato prima subisce un’elaborazione preliminare poi viene eseguito.
  • Un programma che interpreta un linguaggio si dice interprete di quel linguaggio.
  • Un programma che compila un linguaggio si dice compilatore di quel linguaggio.
  • C, C++, Java sono linguaggi compilati
  • Ruby, Python, Javascript sono linguaggi interpretati

Linguaggi debolmente tipizzati

Sono linguaggi che non costringono il programmatore ad assegnare preventivamente alle variabili un tipo specifico di dato. Il tipo di dato viene piuttosto dedotto dal valore a cui la variabile fa riferimento in uno specifico momento dell’esecuzione del programma. Javascript è un linguaggio debolmente tipizzato.

01// Qui si dichiara la variabile x
02var x ;
03 
04// Qui x fa riferimento ad una stringa
05x = "Hello!";
06 
07// Qui x fa riferimento ad un numero intero
08x = 10;
09 
10// Qui x fa riferimento ad un oggetto
11x = { manufacturer: "Ferrari", model: "F355", color: "red" }

Linguaggi dinamici

  • Sono linguaggi che permettono di modificare lo stato di un programma durante l’esecuzione dello stesso (cioé a runtime).

  • Generalmente i linguaggi dinamici sono anche debolmente tipizzati.

  • Javascript è un linguaggio dinamico.

Linguaggi orientati agli oggetti

  • I programmi servono a risolvere problemi in modo efficiente e controllato.

  • I linguaggi orientati agli oggetti permettono di schematizzare il problema mediante una rappresentazione “ad oggetti” dello stesso.

  • Schematizzare un problema mediante oggetti può portare ad una risoluzione più intuitiva dello stesso.

  • Il punto precedente non è sempre vero.

  • Javascript è orientato agli oggetti.

Javascript e HTML/CSS: che c’azzecca?

Vi chiederete: cosa c’entra tutto questo con il web, gli effetti grafici e le animazioni?

Javascript permette di manipolare i contenuti e la visualizzazione della pagina in maniera programmatica. Senza l’intervento di un programma Javascript la struttura di una pagina web risulterebbe “congelata” nella sua scrittura iniziale. Un programma Javascript permette di “scongelare” la struttura di una pagina e di modificarla dinamicamente.

Le Origini

A metà degli anni ‘90, all’alba dell’esplosione del Web come IL servizio Internet per definizione, Brendan Eich entra in Netscape allo scopo di includere nel loro browser un interprete Scheme.

Al tempo in molti (tra cui Bill Joy di Sun) erano convinti e spingevano affinchè il Web avesse un linguaggio di scripting da includere in formato sorgente all’interno delle pagine HTML…

Le influenze… (1/2)

Purtroppo tutto questo interessamento finì per essere controproducente:

la visione del management (di Netscape e di Sun) era che Java (e le applet) sarebbe stato il linguaggio usato dai programmatori per scrivere i componenti mentre questo nuovo linguaggio di scripting sarebbe stato utilizzato dagli scripter per scrivere il codice collante

Le influenze… (2/2)

The diktat from upper engineering management was that the language must "look like Java". That ruled out Perl, Python, and Tcl, along with Scheme.

From Brendan Eich's Roadmap Updates: Popularity

…e le Fonti di Ispirazione (1/2)

I'm not proud, but I'm happy that I chose Scheme-ish first-class functions and Self-ish (albeit singular) prototypes as the main ingredients. The Java influences, especially y2k Date bugs but also the primitive vs. object distinction (e.g., string vs. String), were unfortunate.

From Brendan Eich's Roadmap Updates: Popularity

…e le Fonti di Ispirazione (2/2)

E’ fu così che il progetto inizialmente chiamato Mocha e successivamente chiamato Livescript raggiunse l’inclusione nella versione 2.0 del browser di Netscape:

  • con il nome di Javascript
  • con una sintassi C-like a mascherare un dialetto scheme con estensioni per OOP derivate da Self
  • con una serie di piccoli ma subdoli problemi di coerenza dovuti all’estrema rapidità del passaggio dal prototipo all’ingresso sul mercato (meno di 1 anno!!!)

ECMAScript: la standardizzazione (1/2)

Nel 1996 (lo stesso anno in cui Javascript è stato ufficialmente rilasciato con Netscape Navigator 2.0) Netscape sottopone Javascript alla ECMA International per la standardizzazione:

ECMAScript è il nome della standardizzazione del linguaggio contenuta nello standard ECMA-262 (arrivato alla terza revisione) a cui Javascript (Netscape), JScript (Microsoft) cercano di rimanere compatibili.

ECMAScript: la standardizzazione (2/2)

Oltre allo standard ECMA-262 (alla revisione 3 attualmente in uso) sono presenti altri 3 standard riguardanti Javascript oltre alla revision 4 dello standard ECMA-262:

  • ECMA-290: Components (INUTILIZZATO)
  • ECMA-327: Compact Profile, riduzione dello standard allo scopo di adattarlo a contesti con risorse carenti
  • ECMA-357: E4X (ECMAScript for XML), aggiunge l’xml come first-class-object

ECMAScript: le varianti e le implementazioni (1/4)

Da ECMAScript (oltre a Javascript e JScript) derivano altri linguaggi di scripting, oltre a essere presenti diverse varianti dello stesso dialetto:

  • Javascript (es. SpiderMonkey, Rhino, V8, JavascriptCore/Nitro)
  • ActionScript (es. Adobe Flash)
  • Laszlo ECMAScript (es. OpenLaszlo)
  • HaXe ECMAScript (es. HaXe)

ECMAScript: le varianti e le implementazioni (2/4)

La quarta revisione dello standard ECMA-262 aveva in programma l’introduzione di una notevole quantità di caratteristiche nel linguaggio (tra cui classi e lo static typing)…

ECMAScript: le varianti e le implementazioni (3/4)

… Ma attualmente l’ultima versione dello standard (rilasciata nel Dicembre 2009 con il nome di Harmony) contiene solo alcune lievi modifiche (che costituiscono ora ECMAScript 5) allo scopo di stabilizzare alcune caratteristiche già implementate in diverse varianti, senza stravolgerne la sua natura corrente.

ECMAScript: le varianti e le implementazioni (4/4)

Come è possibile immaginare il cammino dello standard (ECMAScript) è sempre più lento di quello delle implementazioni dovendo mantenere la compatibilità con il passato e tra le varie versioni.

Ogni implementazione (soprattutto quando utilizzata in ambiti diversi delle pagine Web) ha introdotto (e continua ad introdurre) correttivi o nuove caratteristiche al proprio dialetto.

General syntax rules

  • C-like syntax rules
  • commenti in stile C
  • ogni istruzione termina con un punto e virgola ( ”;” )
  • i blocchi di codice sono racchiusi dalle parentesi graffe ( ”{}” )

Javascript Basics

L’interprete interattivo (1/3)

Tutti i linguaggi dinamici sono in genere dotati di un interprete interattivo con cui interagire con la Virtual Machine in maniere interattiva.

Javascript non fa ovviamente eccezione anzi sono molti i modi in cui è possibile ottenere una shell Javascript con cui interagire:

https://developer.mozilla.org/en/JavaScript_shells

L’interprete interattivo (2/3)

  • Javascript Shell
  • Bookmarklet
  • Spidermonkey JS
  • XULRunner xpcshell
  • MozREPL
  • Firebug
  • Venkman
  • Rhino

L’interprete interattivo - JS (3/3)

Il laboratorio integrato accessibile dalle slide di questo corso è dotato di un semplice interprete interattivo (basato su FirebugLite):

1console.log("Hello, world!");
Ora provalo nell'interprete interattivo

Variabili

In Javascript le variabili possono essere dichiarate esplicitamente (mediante la parola chiave var ) o essere utilizzate senza nessuna dichiarazione esplicita:

1var b = "a string"// CORRETTO
2var c;
3 
4a = 5;  // funziona... ma è SCONSIGLIATO
5 
6console.log("a: "+a)
7console.log("b: "+b)
8console.log("c: "+c)

NOTA : E’ assolutamente consigliabile dichiarare sempre esplicitamente le variabili, in quanto quelle utilizzate senza dichiarazione esplicita finiscono nello spazio (“scope”) globale

Ora provalo nell'interprete interattivo

Tipi di dati

  • Number
  • String
  • Object / HashTable
  • Array
  • Boolean

Tipi di dati - Number (1/2)

Javascript ha un solo tipo di numero.

Non distingue quindi tra numeri interi e float ma è dotato di un unico type rappresento internamente come un floating point a 64 bit (identico ad un double Java):

1console.log(1 === 1.0);
2console.log(1 === 1.0e0);
3 
4// ATTENZIONE A QUESTO PERO':
5console.log(0.1 + 0.2);
Ora provalo nell'interprete interattivo

Tipi di dati - Number (2/2)

011
021.0
031.0e3                // 1000
041.0e-3               // 0.001
051 == 1.0             // true
060.1 + 0.2            // 0.30000000000000004
070.2 + 0.09           // 0.29000000000000004
081 / 0                // Infinity
091 / -0               // -Infinity
101 / Infinity         // 0
11 
12(9.3).toFixed(0)     // 9
13(9.6).toFixed(0)     // 10
14(10).toString()        // "10"

Infinity rappresenta tutti i numeri più grandi di 1.79769313486231570e+308

Ora provalo nell'interprete interattivo

Math, parseInt e isNaN

01Math.PI              // 3.141592653589793
02Math.sin(Math.PI/2)  // 1
03Math.floor(2.0+4.5)  // 6
04Math.ceil(2.0+4.5)   // 7
05 
06parseInt("10.0000")   // 10
07parseInt("10.0JJJJ"// 10
08parseInt("AAAAAA 10") // NaN
09 
1010 * "a"              // NaN
11 
12isNaN(10)             // false
13isNaN(NaN)            // true
14isNaN(Infinity)       // false
15 
16NaN == NaN        // false

Math è un built-in object che raccoglie costanti e funzioni matematiche utili, mentre parseInt e isNaN sono funzioni built-in nello “scope” globale.

Ora provalo nell'interprete interattivo

Tipi di dati - String

In Javascript le stringhe sono sequenze di caratteri (Unicode a 16-bit)

1"Hello, World!!!"
2'Hello, World!!!'
3 
4"Javascript".length                // 10
5"Javascript".replace("script",""// "Java"
6"js".toUpperCase()                 // "JS"
Ora provalo nell'interprete interattivo

Tipi di dati - Object/HashTable (1/2)

In Javascript gli oggetti e i dizionari (HashTable) sono sinonimi e costituiscono uno dei concetti fondamentali del linguaggio:

01var flight = {
02  airline: "Oceanic",
03  number: 815,
04  departure: {
05      time: "2004-09-22 14:55",
06      city: "Sydney"
07  },
08  arrival: {
09      time: "2004-09-23 10:42",
10      city: "Los Angeles"
11  }
12};
13 
14flight.status           //undefined
15flight.departure.city       //Sydney
16flight["departure"]["time"] //2004-09-22 14:55
Ora provalo nell'interprete interattivo

Tipi di dati - Object/HashTable (2/2)

1var flight = {};
2 
3flight["status"] = "landed";
4flight.number = 815;

Mentre la chiave (o nome) deve essere necessariamente una stringa, il valore puo’ essere un qualunque oggetto.

Ora provalo nell'interprete interattivo

Tipi di dati - Array

Un Array è uno speciale oggetto built-in:

01var values = [ 10, 20, 30, 40 ];
02 
03values.length        // 4
04values[0]            // 10
05values[10]           // undefined              
06 
07values[50] = 5
08values.length        // 51
09 
10values.join(" - ")   // "10 - 20 - 30 - 40"
11values.slice(0,3)    // [10,20,30]
12values.push(50)      // 5
13values.pop()         // 50
Ora provalo nell'interprete interattivo

Tipi di dati - Boolean

Javascript è dotato di un tipo boolean, con valori (che costituiscono parole chiave) true and false. Tutti i valori possono essere convertiti in boolean secondo le seguenti regole:

  • FALSE: false, 0, la string vuota (””), NaN, null, e undefined
  • TRUE: tutti gli altri valori
01false
02""            // false
030             // false
04NaN           // false
05null          // false
06undefined     // false
07 
08true
09"TEST"        // true
1055            // true
11{}            // true
12Infinity      // true

Operatori (1/4)

Javascript è dotato di tutti gli operatori dei linguaggi con sintassi C-like;

1+ - * / %                     // basic arithmentic operations
2=                             // assignment
3+= -= ++ --                   // increment / decrement operatos
4< > <= >= == != === !==       // comparisons operators
5&& ||                         // boolean operators
6& | ^ ~ << >> >>>             // bitwise operators

Operatori (2/4)

Gli operatori incremento e decremento possono essere usati come operatori sia in prefix che in postfix

L’operatore ”+” viene utilizzato sia per la somma tra numeri che per la concatenazione di stringhe, in caso gli operatori siano di tipo diverso viene operata una conversione forzata, cosa che richiede particolare attenzione:

1"p" + 1 + 1                   // "p11"
21 + 1 + "p"                   // "2p"
Ora provalo nell'interprete interattivo

Operatori (3/4)

Gli operatori di test di uguaglianza in Javascript richiedono ancora più attenzione in quanto le versioni standard ( ”==” / ”!=” ) operano una conversione forzata e silenziosa che potrebbe non dare i risultati che ci si aspetterebbe:

1'' == '0'          // false
20 == ''            // true
30 == '0'           // true
4false == 'false'   // false
5false == '0'       // true
6false == undefined // false
7false == null      // false
8null == undefined  // true
9' \t\r\n ' == 0    // true

NOTA : per questo motivo è sempre consigliabile usare gli operatori ”===” e ”!==” che non effettuano conversioni forzate e silenziose.

Ora provalo nell'interprete interattivo

Operatori (4/4)

typeof ed instanceof sono due particolari operatori il cui compito è rispettivamente identificare il tipo di un valore e verificare se è istanza di un determinato prototipo:

1typeof 10             // number
2typeof "test string"  // string
3typeof true           // boolean
4typeof {}             // object
5 
6var c = {};
7 
8c instanceof Object   // true
Ora provalo nell'interprete interattivo

Strutture di Controllo

  • if, switch
  • while, do…while
  • for, for…in
  • try…catch

Strutture di Controllo - if

Le strutture di controllo di Javascript sono simili alle strutture di controllo classiche dei linguaggi C-like:

01var score = 100, message;
02 
03if (score < 50) {
04  message = "too low!!!";
05} else if (score > 100) {
06  message = "you are god!!!";
07} else {
08  message = "good score!";
09}
10 
11myvar = score >= 20 ? 20 : score;
12 
13myvar = obj && obj.name;
14myvar = name || "default value";
Ora provalo nell'interprete interattivo

Strutture di Controllo - switch

Lo switch (analogo a quello presente nei linguaggi C-like) confronta l’espressione contenuta nella switch con l’espressione contenuta nelle singole clausole case mendiante l’operatore ===:

01switch(action_type) {
02    case 'left_button':
03        open_in_new_tab();
04        break;
05    case 'right_button':
06        open();
07        break;
08    default:
09        alert("unknown action type: "+action_type);
10}

Strutture di Controllo - while / do…while

1while (action_type != 'quit') {
2  // do something
3}
4 
5do {
6  // do something
7} while (action_type != 'quit')

Javascript Basics: Strutture di Controllo - for

1for (var i = 0; i < 5; i++) {
2  // do something
3}
Ora provalo nell'interprete interattivo

Strutture di Controllo - for…in

for…in è una variante della struttura di controllo for utili per iterare su Array ed Object:

1for (var i in [1,2,3]) { print(i); }
2 
3var obj = { key1: "value1", key2: "value2" }
4 
5for (var i in obj) { print(i); }
Ora provalo nell'interprete interattivo

Strutture di Controllo - try…catch (1/2)

Javascript è dotato di un sistema di gestione delle eccezioni con una sintassi del tutto simile agli altri linguaggi C-like:

01// ReferenceError: unknown_function is not defined
02try {
03  unknown_function();
04}
05catch(error) {
06  print(error);
07}
08 
09try {
10  throw new Error("My personal ERROR");
11}
12catch(error) {
13  print(error);
14}

Javascript Basics: Strutture di Controllo - try…catch (2/2)

1try {
2  throw new Error("My personal ERROR");
3}
4finally {
5  print("cleaning!");
6}

Funzioni

  • definire una funzione
  • scope delle variabili
  • functions as objects
  • anonymous functions
  • inner functions
  • closures

Funzioni - definire una funzione

Le funzioni sono sicuramente, insieme agli Object/Hashtables, uno dei costrutti fondamentali per Javascript.

01function sum(a,b) {
02  return a+b;
03};
04 
05var mult = function mult(a,b) {
06  return a*b;
07};
08 
09sum(2,3);     // 5
10sum(2,3,4);   // 5  <----- I parametri aggiuntivi sono ignorati
11mult(2,10);   // 10
Ora provalo nell'interprete interattivo

Funzioni - scope delle variabili (1/2)

In Javascript le variabili dichiarate con var non sono legate al block scope come negli altri linguaggi C-like, ma sono in realtà legate al function scope:

01function test_var_scope() {
02  var a = 5;
03 
04  for (var i = 0; i < a; i++) {
05    var tmp = 200;
06    // do something
07  }
08 
09  print(a);
10  print(i);
11  print(tmp);
12}

Per questo motivo è opportuno dichiarare tutte le variabili utilizzate in una funzione in testa, oltre a non dimenticarsi di dichiararle con var

Ora provalo nell'interprete interattivo

Funzioni - scope delle variabili (2/2)

1function add(a,b) {
2  tot = a+b;
3  return tot;
4}
5 
6test = add(5,6);
7 
8test    // 11
9tot       // 11 <---- tot è finita nel global scope!!!
Ora provalo nell'interprete interattivo

Funzioni - anonymous functions, arguments e arguments.callee (1/2)

In Javascript il nome delle funzioni è opzionale, per cui le funzioni anonime si dichiarano in maniera analoga alle funzioni dotate di un nome.

Inoltre all’interno dello scope di una funzione è possibile accedere ad una variabile simile ad un array che ci da accesso ai parametri e ad un riferimento alla funzione corrente (utile in caso di funzioni anonime):

Funzioni - anonymous functions, arguments e arguments.callee (2/2)

01add = function (a,b) { return a+b; };
02 
03tot = function (a,b) { return a*b; }(5,3);
04 
05count_parameters = function () { return arguments.length; }
06 
07fact =  function (n) {                              
08  if (n == 1) return 1;
09  return n*arguments.callee(n-1);
10}
11 
12fact(3)       
13fact(4)     

Funzioni - functions as objects (1/2)

Le funzioni in Javascript sono First class object (possono essere passate come parametri e ritornate come valori dalle funzioni) e sono dotate di proprietà e metodi come gli altri oggetti.

Funzioni - functions as objects (2/2)

01var add = function add(a,b) {
02  return a+b;
03};
04 
05add.length;               // 2 (il numero di parametri)
06add.call(null,2,3);
07add.apply(null,[2,3]);
08 
09add.toString();
10 
11var obj = {
12  sum: function (a,b) { return a+b; },
13  mult: function (a,b) { return a*b; }
14};
15 
16obj.sum(5,6);
17obj["mult"](3,2);
Ora provalo nell'interprete interattivo

Funzioni - inner functions

In Javascript è consentito dichiarare una funzione all’interno di un’altra funzione:

01function do_alot_of_stuff(param1, param2) {
02   var tot;
03 
04   // do stuff...
05    
06   tot = sum(param1,param2);
07 
08   // do other stuff...
09    
10   return tot;
11 
12   function sum(a,b) { return a+b; };
13}

NOTA: non ha importanza dove vengono dichiarate le inner function , è come se tutte le funzioni fossero valutate all’inizio della funzione.

Funzioni - closures (1/3)

Le closure sono una importantissima caratteristica delle funzioni in Javascript, sulla quale si poggiano sia i meccanismi di Event Handling usati solitamente nello scripting Web, che molte delle tecniche per completare la OOP di Javascript o ovviare ad alcuni dei suoi difetti di design.

Le closure in Javascript sono costituite dalle normali funzioni, le quali portano con se il lexical scope nelle quali sono state definite.

Funzioni - closures (2/3)

01function mult(n) {
02  return function(a) {
03    return a*n 
04  };
05};
06 
07double = mult(2);
08 
09double(5);             // 10
10double(4);             // 8
11 
12half = mult(0.5);
13 
14half(5);               // 2.5
15half(4);               // 2
16 
17mult(0.5)(4);          // 2
Ora provalo nell'interprete interattivo

Funzioni - closures (3/3)

01var test_obj = function() {
02  var private_var = 100;
03 
04  return {
05    get_private_var: function() { return private_var; },
06    step: function() { private_var++;}
07  }
08}();
09 
10test_obj.get_private_var();
11test_obj.step();
12test_obj.get_private_var();
Ora provalo nell'interprete interattivo

Javascript Bad Parts

Special values

Ci sono alcuni valori in Javascript che hanno comportamente particolarmente poco amichevoli:

Special Values

  • undefined
  • null
  • NaN
  • Infinity
  • true, false

Special Values

  • undefined e null hanno significati diversi
  • typeof null ritorna ‘object’
  • NaN non è un numero ma typeof lo riporta come number,
  • NaN, undefined e Infinity non sono parole registrate e possono erroneamente essere ridefinite :-( … cosa che è meglio evitare :-D

primitive vs. object

Se questo non bastasse… Javascript ha ereditato da Java la differenza fra primitiva e istanza del relativo oggetto:

01typeof "test string"                          // 'string'
02typeof new String("test string")              // 'object'
03"test" instanceof String                      // false
04new String("test string") instanceof String   // true
05 
06typeof true                                   // 'boolean'
07typeof new Boolean(true)                      // 'object'
08 
09typeof 10                                     // 'number'
10typeof new Number(10)                         // 'object'

NOTA : per questo motivo è sempre meglio utilizzare esclusivamente le primitive per i tipi dati primitivi (string, boolean, number e function)

Ora provalo nell'interprete interattivo

Bibliografia

Javascript The Good Parts (O’Reilly)

Copyright (C) 2010 - Alca Società Cooperativa

http://learn.alcacoop.it - learn@alcacoop.it

released under CreativeCommons 2.5 by-nc-sa