15 Javascript

download 15 Javascript

of 84

Transcript of 15 Javascript

Universit degli Studi di Bologna Facolt di Ingegneria Anno Accademico 2010/2011 Capitolo 15 JAVASCRIPT: UN LINGUAGGIO SORPRENDENTE Approccio funzionale & a oggetti "all in one" Prof. Enrico DentiDEIS 051.20.93015

[email protected]

PERCH JAVASCRIPT ? Perch incorpora molte caratteristiche interessanti, spesso ignote: ben oltre lo scripting per pagine web! Perch adotta segue un approccio funzionale, con funzioni e chiusure concetti fondamentali di computer science qui offerti in forma semplice e pratica Perch adotta un modello object-based senza classi, basato sul concetto di prototipo Perch un linguaggio interpretato, con aspetti dinamici di grande interesse ottima palestra per sperimentare Perch adatto a creare applicazioni multi-paradigma In breve, perch unisce potenza espressiva a un modello computazionale interessante, potente e flessibile !

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

1

PERCH NON JAVASCRIPT ? Perch incorpora anche alcuni "errori di giovinezza" in effetti, passato dalla "non esistenza" all'ampia adozione in (troppo) poco tempo: non ci fu il tempo per "ripulirlo"

Perch soffre qua l di alcune pessime idee (oltre alle tante ottime idee) la peggiore: un ambiente globale (pure mal definito!) con variabili globali ci pu portare a stili che non rispettano le buone pratiche.. ma che si possono evitare, con adeguate scelte e disciplina

Perch alcune caratteristiche sono controverse il loose typing riduce le possibilit di intercettare errori di tipo, MA potente, molto flessibile, ed evita i cast d'altronde, anche lo strong typing non elimina la necessit di testing

l'ereditariet prototype-based concettualmente potente, ma non sempre facile da seguire per chi viene da linguaggi "class based"

1. LE BASI DEL LINGUAGGIO 2. IL LATO FUNZIONALE 3. IL LATO A OGGETTI 4. DOVE I DUE LATI S'INCONTRANO 5. APPLICAZIONI MULTI-PARADIGMA

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

2

JAVASCRIPT: LE BASI Nasce come linguaggio di scripting inventato da Netscape (LiveScript), rinominato in JavaScript nel 1995 dopo un accordo con Sun Microsoft ha la sua variante, JScript (minime differenze) standard: ECMAScript 262

Object-based (ma non object-oriented) simile a C, Pascal, Java...ma di Java ha "piuttosto poco": anzi, assomiglia pi ai linguaggi funzionali come Lisp

Come si usa: i programmi Javascript si includono di solito nel sorgente HTML delle pagine Web e sono eseguiti nel browser Javascript Virtual Machine: Rhino, SpiderMonkey (Mozilla: v. anche TraceMonkey), V8 (Google), JScript (Microsoft) V8 (C++), Rhino (Java), SpiderMonkey (C) sono usabili anche stand alone

Inserimento nelle pagine web ... ...

Una pagina HTML pu contenere pi tag .

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

3

Elementi linguistici: stringhe Il tipo string denota stringhe di caratteri Unicode non esiste il tipo char: un carattere una stringa lunga 1 ogni stringa un oggetto IMMUTABILE dotato di propriet, tra cui length, e di metodi, tra cui substring (indici first, last come in Java last indica il primo escluso)

Le costanti stringa possono essere delimitate sia da virgolette sia da apici singoli se occorre annidare virgolette e apici, occorre alternarli: document.write('') document.write("")

Le stringhe si possono concatenare con l'operatore +ma attenzione in presenza di numeri: document.write(beta + alfa + 2) document.write(beta + (alfa + 2))

Elementi linguistici: numeri Il tipo number denota un reale a 64 bit non ci sono interi, quindi non esistono problemi di overflow o errori legati a conversioni numeriche la divisione quindi sempre fra reali, anche con operandi apparentemente interi (esempio: 7/3 = 2.33333) gli operatori bitwise operano su interi ottenuti convertendo un reale sono lentissimi e inefficienti: evitare!

Le costanti numeriche sono sequenze di caratteri numerici non racchiuse da virgolette o apici la costante NaN rappresenta il "risultato" di operazioni impossibili: non uguale ad alcun valore, incluso se stessa un'operazione che coinvolga un NaN d come risultato NaN la costante Infinity rappresenta un valore maggiore del massimo reale positivo rappresentabile (1.79 * 10+308)

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

4

Elementi linguistici: altri Le costanti booleane sono true e false Il loro tipo boolean ma attenzione alla valutazione delle condizioni nelle strutture di controllo (v. oltre)

Altre costanti sono null e undefined undefined indica un valore indefinito

I commenti hanno le classiche forme: a riga singola su pi righe // commento su riga singola /* commento su pi righe */

OCCHIO a commentare blocchi di codice con espressioni regolari: in esse possono comparire stringhe come "*/"

Espressioni Sono consentite sostanzialmente le stesse espressioni lecite in Java espressioni numeriche: somma, sottrazione, prodotto, divisione (sempre fra reali), modulo, shift, espressioni condizionali con ? : espressioni stringa: concatenazione con + espressioni di assegnamento: con = (e sue varianti)

Esempi:document.write(18/4) // fra reali document.write(18%2) document.write("paolino" + 'paperino')

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

5

Variabili Le variabili in Javascript sono loosely typed possibile assegnare alla stessa variabile prima un valore di un tipo, poi un valore di un altro tipo! Ad esempio: alfa = 19 beta = "paperino" alfa = "zio paperone" // tipo diverso!! Sono consentiti incrementi, decrementi e operatori di assegnamento estesi (++, --, +=, )

Dichiarazione implicita o esplicita La dichiarazione di una variabile pu essere implicita (la si usa e basta) o esplicita (con la parola chiave var) Esempio: var pippo = 19 pluto = 18 // dichiarazione esplicita // dichiarazione implicita

La dichiarazione implicita introduce sempre e solo variabili globali La dichiarazione esplicita pu introdurre variabili globali o locali, a seconda di dove compare.

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

6

Tipo dinamico Il tipo (dinamico) di una espressione (variabili incluse) ottenibile tramite l'operatore typeof : typeof(18/4) d number typeof("aaa") d string typeof(false) d boolean typeof(document) d object typeof(document.write) d function anche se talvolta typeof restituisce risultati inattesi: ad esempio, typeof([1,2,3]) d object anzich array

Se usato su variabili, typeof restituisce il tipo attuale della variabile (o dell'oggetto): a = 18; typeof(a) d number a = "ciao"; typeof(a) d string

Istruzioni Le istruzioni devono essere separate una dall'altra o da un fine riga, o da un punto e virgola (similmente al Pascal e diversamente dal C o da Java) Esempio:alfa = 19 // fine riga beta = "paperino" ; gamma = true document.write(beta + alfa)

ATTENZIONE alle conseguenze: ("semicolon insertion") se si va a capo dove non si deve Esempio:return 18; return 18; // restituisce 18 // restituisce undefined // (statement irraggiungibile)

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

7

Strutture di controllo Javascript dispone delle usuali strutture di controllo if, switch, for, while, do/while pi due specifiche per operare su oggetti: for in e with ATTENZIONE: il for..in di JavaScript non equivalente al foreach di Java/C# poich itera sui nomi degli elementi della collezione, non sugli elementi stessi per gli array, i nomi degli elementi sono gli indici (0,1,2) una caratteristica utile per gli array associativi, che per pu risultare fuorviante se sconosciuta o inattesa il for classicov = [13,24,37]; for (i=0; i < v.length; i++) document.write( v[i] ); // stampa 13,24,37

il forinv = [13,24,37]; for ( item in v ) document.write( item ); // stampa 0,1,2

Operatori relazionali Le operatori relazionali sono i soliti (==, !=, >, =, // horizontal problem p1.getX()p2.getX() ? 1 : 0) } ); in futuro (Java 8) PASSO 2 (con librerie rivisitate) Collections.sortBy(mylist, #{ Point p -> p.getX() } ); dove sortBy prevede come secondo argomento non pi un Comparator, ma soltanto un Extractor che si limiti a estrarre una chiave di confronto (Comparable). in futuro (Java 8) PASSO 3 (con librerie rivisitate e method reference) Collections.sortBy(mylist, #Point.getX ); in futuro (Java 8) PASSO 4 (con extension methods) mylist.sortBy( #Point.getX ); // o forse Point#getX

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

31

Chiusure in C# e ~Java8: cenni implementativi Sia C# sia Java 8 supportano le chiusure convertendole in qualche genere di codice equivalente in C#, il codice equivalente si basa sul delegato "naturale" per quella espressione (+ una interfaccia + invoke): ad esempio,{ int x, int y => x+y } { => Console.WriteLine("..")} tipo: { int,int => int } tipo: { => void }

in Java8, il codice equivalente si basa su una classe anonima derivata dall'interfaccia SAM (Single Abstract Method) associata all'espressione lambda

Conseguentemente: in C#, le lambda expression sono assimilate a normali interfacce, con piena interoperabilit con tutte le API esistenti in Java8, le lambda expression sono gestite diversamente e ristrette a situazioni specifiche (SAM-convertible contexts), ma non per questo sono meno potenti.

Chiusure in Java8: come, dove, quando Come avviene la conversione in lambda / SAM ? Ammesso che esista una interfaccia SAM: public interface CallbackHandler { public void callback(Context c); } un riferimento a essa costituisce un tipo lecito per la lambda expression corrispondente: CallbackHandler ch = #{ Context c -> System.out.println("hi!") } in quanto tale lambda expression prende in ingresso un argomento Context, ha tipo di ritorno void e non lancia eccezioni.

Dove pu apparire una lambda expression in Java8? SOLO dove pu essere convertita nel tipo-SAM corrispondente OVVERO in assegnamenti, cast, invocazioni di metodi

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

32

Chiusure in Java8: come, dove, quando Perch si possono referenziare variabili locali solo final? Perch le variabili locali "non final" sono tipicamente usate in idiomi sequenziali, dove permettere di referenziarle rischierebbe di creare facilmente corse critiche, creando solo nuovi problemi. Esempio di idioma NON permesso: int sum = 0; mylist.foreach(#{ elem -> sum+= elem.size(); }); a meno di non vincolare il multi-threading, difficile scrivere bodies che non abbiano corse critiche a qualche livello

necessaria la qualifica esplicita final ? attualmente (Java 6) s, ma in Java 8 NO perch il compilatore effettuer una forma di type inference: conter la sostanza il compilatore accetter variabili non formalmente final che per siano effettivamente final, ovvero in cui l'aggiunta della qualifica final non causi errore di compilazione.

MODELLI COMPUTAZIONALI PER LA VALUTAZIONE DI FUNZIONI Ogni linguaggio che preveda funzioni deve prevedere un modello computazionale per la loro valutazione. Tale modello deve in particolare stabilire: QUANDO si valutano i parametri COSA si passa alla funzione COME si attiva la funzione (si cede il controllo ?)

Tradizionalmente, il pi usato il modello applicativo: QUANDO si valutano i parametri: subito, prima di ogni altra cosa COSA si passa alla funzione: di solito, il valore dei parametri [a volte, per certi tipi o a esplicita richiesta: il loro indirizzo] COME si attiva la funzione: tipicamente, chiamandola e cedendo il controllo [modello sincrono si attende che essa termini]

Tuttavia, esso ha alcuni difetti.

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

33

MODELLO APPLICATIVO: VANTAGGI E LIMITI Il modello applicativo molto usato perch semplice e nel complesso efficiente valuta i parametri una sola volta per ogni chiamata passa dei valori (entit tipicamente snelle e semplici da gestire) o al limite indirizzi (entit egualmente snelle e semplici) rende facile seguire il flusso di esecuzione (leggibilit)

Tuttavia, valutando i parametri a priori pu causare inefficienze e soprattutto fallimenti non necessari infatti, valutando i parametri sempre e comunque, pu fare lavoro inutile se alcuni di essi non risultano poi necessari in quella chiamata ma soprattutto, se la valutazione di uno di tali parametri d errore (o eccezione), questo modello causa un fallimento che si sarebbe potuto evitare con un approccio diverso.

MODELLO APPLICATIVO: ESEMPI DI FALLIMENTI EVITABILIEsempio in Javaclass Esempio { static void printOne(boolean cond, double a, double b){ if (cond) System.out.println("result = " + a); else System.out.println("result = " + b); } public static void main(String[] args) { int x=5, y=4; printOne(x>y, 3+1, 3/0); //ArithmeticException: / by zero } }

In questo esempio, la valutazione dei parametri attuali causa eccezione, ma in realt in questa chiamata il parametro b non sarebbe stato usato perch x>y vera fallimento evitabile! Con un diverso modello computazionale, questa invocazione avrebbe potuto avere successo!

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

34

MODELLO APPLICATIVO: ESEMPI DI FALLIMENTI EVITABILIEsempio in JavaScriptvar f = function(flag,x) { return (flag obj = { run: function(){ print(running...) }}; definisce il metodo run. js> r = new java.lang.Runnable(obj); js> t = new java.lang.Thread(r); Thread[Thread-0,5,main] Istruzione errata in Java (Runnable js> t.start(); un' interfaccia, non ha costruttori!) js> running...ma corretta in Rhino dove viene interpretata come creazione di un wrapper delloggetto Javascript obj

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

81

Scripting Java da Rhino:il costruttore JavaAdapterLapproccio precedente: non consente di implementare interfacce multiple; permette di estendere solo interfacce o classi astratte.JavaAdapter( javaInterfaceOrClass, [javaInterfaceOrClass, ...], javascriptObject)Interfaccia o classe Java

Oggetto JavaScript che estende le classi e implementa le interfacce. Lereditariet usa gli stessi meccanismi di Java (ereditariet multipla delle sole interfacce)

Scripting Java da Rhino:un esempio completoTutti questi metodi saranno ereditati a runtime da java.awt.Frame.

LactionListener per il Button pu essere tranquillamente agganciato e modificato a runtime.

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

82

Embedding Rhino in JavaPer eseguire uno script Rhino in Java, occorrono: un contesto, per mantenere le informazioni thread-specific oggetto Context uno scope, per mantenere le informazioni script-specific (variabili globali, oggetti standard, etc) oggetto Scope lo script, sotto forma di stringa o di Reader da cui leggerlo un dominio di sicurezza, in cui eseguirlo (anche null)

L'esecuzione effettiva poi lanciata dai metodi:Object evaluateString(scope, source, , securityDomain) Object evaluateReader(scope, source, , securityDomain)

Embedding Rhino in Java:Context & Scope Un Context mantiene le informazioni thread-specific sullambiente di esecuzione di uno script Context ctx = Context.enter() associa il thread corrente ad un Context e lo restituisce Context.exit() rilascia il contesto

Uno Scope un set di oggetti JavaScript che mantiene le informazioni script-specific sull'ambiente di esecuzione: Variabili globali dello script; Oggetti standard (Function, Object...)

Viene creato da un Context, ma indipendente da esso: ScriptableObject scope = ctx.initStandardObjects();

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

83

Embedding Rhino in Java:Esempio di esecuzioneObject evaluateString( Scriptable scope, String source, String sourceName, int lineNumber, Object securityDomain )// creazione del contesto Context ctx = Context.enter(); // creazione e inizializzazione dello scope SecurityDomain nullo ScriptableObject scope = ctx.initStandardObjects(); nessuna politica di // definizione del testo del programma JavaScript sicurezza String script = java.lang.System.out.println(hello world!); // esecuzione dello script Object result = ctx.evaluateString(scope, script, Mia Prova, 1, null); // Stampa del risultato System.out.println( ctx.toString(result) ); Numero di riga // Esco dal contesto Strnga stampata dell'eventuale errore Context.exit(); su stderr in caso stampato su stderr di errore (utile a (utile per debugging) fini di debugging)

Non finisce qui Grazie a Rhino si possono: Usare oggetti JavaScript da Java; Wrappare oggetti Java in oggetti JavaScript; Tradurre sorgenti JavaScript in bytecode Java (JavaScript Compiler: http://www.mozilla.org/rhino/jsc.html); Effettuare il debug del codice JavaScript: (Rhino Debugger: http://www.mozilla.org/rhino/debugger.html).

Prof. Enrico Denti - Universit di Bologna A.A. 2010/2011

84