javascript

Transcript

javascript
javascript
crash course
Vittorio Maniezzo – University of Bologna
1
javascript
JavaScript è un linguaggio di programmazione:
• funzionale
• interpretato
• orientato agli oggetti
• con garbage collection.
JavaScript è stato sviluppato in 10 giorni nel maggio
1995 da Brendan Eich, che lavorava a Netscape, come
linguaggio di scripting HTML per il proprio browser
Navigator 2
Vittorio Maniezzo – University of Bologna
2
1
JavaScript
JavaScript è il linguaggio del web.
Può essere usato per:
• Implementare una applicazione con memorizzazione dati
locale o remota.
• Implementare un componente front-end per una applicazione
web distribuita, con dati in remoto gestiti da un componente
server-side (PHP, Java, C#).
• Implementare una applicazione web distribuita completa,
dove sia il front-end che il back-end sono programmi
JavaScript (es., con NodeJS).
• Arricchire una pagina web con codifica dinamica del DOM.
Vittorio Maniezzo – University of Bologna
3
Il linguaggio in un lucido
// Un commento
var x;
//
x = 3 + y; //
foo(x, y); //
obj.bar(3); //
in linea, inizia con due slash
dichiarazione di una variabile
assegnamento di un valore a una variabile`x`
chiamata della funzione`foo`con parametri`x`e y`
chiamata del metodo`bar`dell’oggetto`obj`
if (x === 0) { x = 123; } // condizionale
// definizione della funzione foo`con parametri`a`e`b`
function foo(a, b) { return a + b; }
Vittorio Maniezzo – University of Bologna
4
2
Eseguire il codice
Il codice può essere messo in esecuzione in due modi:
• In un browser, inserendolo come script in una
pagina html
<head>
<script type="text/javascript">
function print(text) { document.querySelector("#output").innerHTML += text + "\n"; }
</script>
<script type="text/javascript" src="code.js"></script>
</head>
<body>
<pre id="output"></pre>
<script type="text/javascript">
print("Ciao bello!");
</script>
</body>
• Standalone, ad esempio richimandolo da node.js
Vittorio Maniezzo – University of Bologna
5
Tipi di dati
• Tre tipi di dati primitivi: string, number e boolean.
• Tre tipi by reference: object, array e function.
• Gli array e le funzioni sono solo oggetti particolari.
• I tipi non sono dichiarati e non sono controllati
(JavaScript non è compilato).
• La conversione dei tipi (casting) è fatta
automaticamente.
Vittorio Maniezzo – University of Bologna
6
3
Valori
Il valore di una variabile può essere
• Un dato: una stringa, un numero, un booleano,
• Un puntatore a un oggetto (reference): riferimento a
un oggetto, a un array, o a una funzione,
• Uno dei due valori speciali: undefined o null.
Vittorio Maniezzo – University of Bologna
7
Valori numerici
Tutti i valori numerici sono sempre rappresentati come
64-bit floating point con esponente opzionale (es.
3.1e10).
Non c’è distinzione fra integer e floating point.
Per assicurarsi che un numero sia un integer si può
applicare la funzione parseInt (numero come stringa e
taglia al .)
Se una espressione numerica non produce un numero, il
suo valore diventa NaN ("not a number").
Vittorio Maniezzo – University of Bologna
8
4
Valori Booleani
Due letterali Booleani: true e false
Gli opertori Booleani sono quelli del c: ! per NOT, && per AND, ||
per OR.
Un valore non Booleano usato in una espressione Boolean viene
convertito in un valore Booleano così:
•
Stringa vuota, numero 0, undefined e null, sono false,
•
Tutti gli altri valori sono true.
Per il test, due possibilità: triple equality symbol === e !==
oppure double equality == e !=.
I tripli evitano casting automatico, (2 === "2") è false mentre
(2 == "2") è true
Vittorio Maniezzo – University of Bologna
9
Array e oggetti: inizializzazone
Array: può essere fatta assegnando il letterale di array
vuoto, var a = [], o invocando il costruttore della
classe Array(), var a = new Array().
Oggetti: può essere fatta assegnando il letterale di
oggetto vuoto, var o = {} , o invocando il costruttore
della classe Object(), var o = new Object().
Il letterale oggetto vuoto, {}, non è vuoto, ma contiene
proprietà e metodi ereditati da Object.prototype.
Per cerare un oggetto davvero vuoto si usa
Object.create(null).
Vittorio Maniezzo – University of Bologna
10
5
Scope delle variabili
Nella versione ECMAScript 5 di JavaScript, ci sono solo due scope:
globale e funzione, non il blocco.
Dichiarare una variabile in un blocco è ammissibile, ma è come
dichiararla a inizio funzione (hoisting):
function foo()
{ for (var i=0; i < 10; i++) { ... }
}
E’ come:
function foo()
{ var i=0;
for (i=0; i < 10; i++) { ... }
}
Tutte le variabili non dichiarate vengono assunte avere uno scope
globale. Evitarle! (magari in una libreria che linkate ne usano una
con lo stesso nome)
Vittorio Maniezzo – University of Bologna
11
Strict mode
Lo strict mode istanzia un più stretto error checking a
runtime.
Per esempio, in strict mode tutte le variabili devono
essere dichiarate e un assegnamento a una variabile
non dichiarata genera una eccezione.
Per attivare lo strict mode si inserisce come prima linea
del file JavaScript file o dello <script> :
"use strict";
Vittorio Maniezzo – University of Bologna
12
6
Oggetti
A differenza dell’OO standard, in JS gli oggetti non sono
necessariamente istanze di una classe.
Gli oggetti possono essere creati senza istanziare una classe:
var obj1 = { lastName:“Maniezzo", firstName:“Vittorio"};
var obj2 = Object.create( null );
// oggetto vuoto, senza slot
Un oggetto è un insieme di coppie attributo-valore (name-valuepairs), dette slot, che possono essere:
• proprietà (property slot), obj1.firstName = "pippo";
• funzioni (function slot), obj1.getName: function () { return obj.firstName; }
• chiavi di una mappa associativa (key-value slot).
Vittorio Maniezzo – University of Bologna
13
Proprietà e metodi
L’attributo in un property slot può denotare:
• Una proprietà data-valued, quindi il valore è (una
espressione che calcola) un dato;
• Una proprietà object-valued, quindi il valore è un
riferimento ad un oggetto o, più in generale, una
espressione che definisce un oggetto.
L’attributo in un method slot denota una funzione (un
metodo), il suo valore è il testo con il sorgente della
funzione.
Vittorio Maniezzo – University of Bologna
14
7
Accesso alle proprietà
Le proprietà degli oggetti possono essere utilizzate in
due modi:
Con la notazione a punto (come c#/c++/Java):
obj1.lastName = “Maniezzo"
Con la notazione tipo mappa associativa:
obj1["lastName"] = “Maniezzo"
Vittorio Maniezzo – University of Bologna
15
Oggetti: utilizzo
Casi d'uso :
• record: è un insieme di property slots:
var myRecord = {firstName:"Tom", lastName:"Smith", age:26}
• map ('associative array'): permette il recupero di valori sulla
base di chiavi (stringhe !! ):
var numeral2number = {"one":"1", "two":"2", "three":"3"}.
• untyped object: non è istanza di una classe, ma può avere
property slot e function slot:
var person1 = { lastName: "Smith", getInitial: function () {
return this.lastName.charAt(0); } };
• namespace: un untyped object referenziato da una variabile
globale che rappresenta un namespace prefix:
var myApp = { model:{}, view:{}, ctrl:{} };
• typed object: instanzia una classe che è definita o da un
costruttore C o da un factory object F.
Vittorio Maniezzo – University of Bologna
16
8
Array
Un array, in realtà un'array list, è una lista dove ogni elemento può
essere individuato con un indice numerico.
Inizializzazione: var a = [1,2,3];
Gli array possono crescere dinamicamente, si possono usare indici
maggiori della lunghezza dell'array. Per es., con un array lungo 3, si
può assegnare il quinto elemento a[4] = 7;
Il contenuto può essere visitato con un for:
for (i=0; i < a.length; i++) {...}
Vittorio Maniezzo – University of Bologna
17
Array
Per aggiungere un elemento in coda all'array:
a.push(newElement);
per cancellare un elemento in posizione i dall'array a:
a.splice(i, 1);
Per cercare l'indice di un elemento di valore i nell'array a (-1 se
non lo trova) :
if (a.indexOf(v) > -1) ...
Per visitare tutti gli elementi, for o foreach (se array piccolo):
var i=0; for (i=0; i < a.length; i++) { ... }
a.forEach( function (elem) { console.log( elem); })
Per clonare un array a:
var clone = a.slice(0);
Vittorio Maniezzo – University of Bologna
18
9
Map
Una map ('hash map', 'associative array') implementa un mapping
da chiavi a valori associati. Le chiavi sono stringhe:
var myTrad = { "my house": “mia casa",
“my boat“ : “mia barca"}
La funzione Object.keys(m) permette di elencare tute le chiavi di
una map:
var i=0, key="", keys=[];
keys = Object.keys( myTrad);
for (i=0; i < keys.length; i++)
{ key = keys[i];
alert(‘La traduzione di '+ key +' è '+ myTrad[key]);
}
Vittorio Maniezzo – University of Bologna
19
Map
Per aggiungere una nuova entry:
myTrad["my car"] = “mia auto";
Per cancellare una entry:
delete myTrad["my boat"];
Per cercare un elemento di chiave data:
if ("my bike" in myTrad) ...
Per passare tutti gli elementi di una map m, prima Object.keys poi
for oppure forEach:
var i=0, key="", keys=[];
keys = Object.keys(m);
for (i=0; i < keys.length; i++)
{ key = keys[i]; console.log(m[key]); }
oppure, se m è piccola:
Object.keys(m).forEach( function (key) {console.log(m[key]); })
Vittorio Maniezzo – University of Bologna
20
10
Funzioni
Le funzioni sono oggetti. Possono essere assegnate a variabili,
passate come argomenti ad alte funzioni, ritornate da funzioni,
avere proprietà e venire cambiate dinamicamente.
La forma generale della definizione di una funzione è un
assegnamento ad una variabile:
var myFunction = function theNameOfMyFunction () {...}
dove theNameOfMyFunction è opzionale, se non lo si mette la
funzione è anonima.
Le funzioni sono invocate attraverso la variabile che referenzia la
funzione, cioè via myFunction() e non theNameOfMyFunction().
Vittorio Maniezzo – University of Bologna
21
Funzioni anonime (lambda)
Esempio di funzione anonima passata come argomento ad un’altra
funzione: ordinamento di un array list di coppie di numeri in ordine
lessicografico.
La funzione di confronto deve ritornare <0 se primo argomento
minore del secondo, >0 se maggiore e =0 se uguali.
var list = [[1,2],[1,3],[1,1],[2,1]];
list.sort( function (el1,el2) {
return ((el1[0] === el2[0]) ? el1[1]-el2[1] : el1[0]-el2[0]);
});
Vittorio Maniezzo – University of Bologna
22
11
Funzioni
La dichiarazione di una funzione ha la forma:
function unaFunzione() {...}
o, equivalentemente:
var unaFunzione = function unaFunzione() {...}
Entrambe creano sia una funzione di nome unaFunzione che una
variabile unaFunzione che la referenzia.
Le funzioni possono avere funzioni interne. La closure in JavaScript
permette alla funzione interna di accedere a tutte le variabili di
quella esterna, al momento della sua creazione.
Esempio:
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
Vittorio Maniezzo – University of Bologna
23
Classi
In JavaScript non c’è una gestione esplicita delle classi, ma le si
può definire in due modi diversi:
• attraverso una funzione costruttore che permette di creare
nuove istanze tramite l’operatore new.
• attraverso un factory object che usa il metodo predefinito
Object.create per creare le nuove istanze.
Inoltre, gli oggetti possono essere creati anche senza creare
un'istanza di una classe, nel qual caso non sono tipizzati.
In fase di esecuzione, metodi e proprietà possono sempre essere
aggiunti a o rimossi da qualsiasi oggetto e classe.
Vittorio Maniezzo – University of Bologna
24
12
Classi: costruttore
Una classe con costruttore può essere definita come segue.
1. Definire un costruttore che specifica le proprietà della classe e
assegna i valori passati coi parametri del costruttore:
function Person(cognome) {
this.lastName = cognome;
}
2. Definire i metodi delle istanze come method slot della proprietà
prototype del costruttore:
Person.prototype.getInitials = function () {
return this.lastName.charAt(0);
}
3. Definire i metodi statici della classe come method slot del
costruttore
Person.checkName = function (n) {
... }
Vittorio Maniezzo – University of Bologna
25
Classi: costruttore
Una istanza si crea attraverso una new:
var pers1 = new Person"Maniezzo");
I metodi sono invocati sull’oggetto tramite la notazione col punto:
alert("The initial of the person is: " + pers1.getInitials());
Il tipo (classe) dell’oggetto creato può essere recuperato tramite
pers1.constructor.name che ritorna "Person".
L’eredità è garantita sui metodi, che vengono ereditati attraverso
la proprietà prototype del costruttore.
Le altre proprietà non sono ereditate nello stesso modo.
Vittorio Maniezzo – University of Bologna
26
13
Classi: factory based
Si definisce un oggetto Person (che rappresenterà una classe) che contiene un
metodo speciale, create, che invoca il metodo predefinito Object.create per
crearne le istanze:
var Person = {
typeName: "Person",
properties: {
firstName: {range:"NonEmptyString", label:"First name", writable: true},
lastName: {range:"NonEmptyString", label:"Last name", writable: true}
},
methods: {
getInitials: function () {
return this.firstName.charAt(0) + this.lastName.charAt(0);
}
},
create: function (slots) {
var obj = Object.create( this.methods, this.properties);
Object.defineProperty( obj, "type", {value: this, writable: false, enumerable: true});
Object.keys( slots).forEach( function (prop) {
if (prop in this.properties) obj[prop] = slots[prop];
})
return obj;
}
};
Una istanza della classe Person viene generate invocandone il metodo create:
var pers1 = Person.create( {firstName:“Vit", lastName:“Man"});
Vittorio Maniezzo – University of Bologna
27
Callback functions
Una funzione di callback è una funzione che viene passata a
un'altra funzione come parametro, ed eseguita all'interno della
funzione esterna.
Passando la funzione di callback come argomento, se ne passa
solo la definizione: la funzione di callback non viene eseguita
immediatamente ma ri-chiamata (called back) in un punto
all'interno del corpo della funzione che lo contiene (la callback è
una closure).
var friends = [“Anna", “Bea", “Carla"];
friends.forEach(function (eachName, index){
console.log(index + “ - " + eachName);
});
(forEach ha due overload, con 1 o 2 parametri)
Vittorio Maniezzo – University of Bologna
28
14
Callback functions
Le callback sono molto utili per gestire eventi asincroni
function getScript(callback)
{ var script = document.createElement('script');
script.src = 'http://da_qui_il_codice';
document.getElementsByTagName('head')[0].appendChild(script);
//dopo l’evento load dello script, si esegue la callback
script.onload = callback;
};
// chiamata nel codice
getScript(function(){ console.log(“caricato lo script"); });
Vittorio Maniezzo – University of Bologna
29
Callback functions
La funzione non deve per forza essere anonima, in questo caso si
può passare il nome.
// funzione che stampa a console
function logStuff (userData)
{ console.log(userData);
}
// due parametri, il secondo è una callback function
function getInput (options, callback)
{ callback (options);
}
// chiamata nel codice
getInput ({nome:“Pippo", anni:“103"}, logStuff);
Vittorio Maniezzo – University of Bologna
30
15
EcmaScript 6
ECMAScript 6 è la versione di giugno 2015 dello standard
ECMAScript (http://www.ecma-international.org/ecma262/6.0/ , ma c’è già anche la 7), molte modifiche sintattiche.
Implementazione avanzata in molti browser:
http://kangax.github.io/compat-table/es6/
Nuovi elementi in ES6:
arrows
classes
enhanced object literals
template strings
destructuring
default + rest + spread
let + const
iterators + for..of
generators
Unicode
modules
module loaders
proxies
symbols
Map, set (weakmap, weakest)
subclassable built-ins
promises math,number,string,array,object APIs
binary and octal literals
reflect api
tail calls
Vittorio Maniezzo – University of Bologna
31
Block−scoped variables
for (let i = 0; i < a.length; i++)
{
let x = a[i]
…
}
Vittorio Maniezzo – University of Bologna
32
16
Arrow Functions
Sintassi più espressiva per le clusure, usano l’operatore
=> per definire delle lambda.
Sintatticamente molto simili all’equivalente C#,
// Statement bodies
var nums = [1,2,3];
nums.forEach(v => { if (v % 5 === 0)
fives.push(v);
});
Vittorio Maniezzo – University of Bologna
33
Destructuring assignment
Object and array matching
Destrutturazione di array e oggetti in variabili
durante un assegnamento
// array
var list = [1, 2, 3]
var [a, , b] = list
var [x, ...y] = ['a', 'b', 'c'];
// x = 'a', y = ['b', 'c'] ... è l’operatore resto
/* object: se il valore di una property è assegnato a
una variabile col nome uguale a quello della
property, lo si può omettere */
var {x, y} = {x: 11, y: 8};
console.log(x)
// 11
console.log(y)
// 8
Vittorio Maniezzo – University of Bologna
34
17
Moduli: export/import di valori
Supporto a export/import di valori da/per moduli
senza invader i namespace.
// lib/math.js
export function sum (x, y) { return x + y; }
export var pi = 3.141593
// someApp.js
import * as math from "lib/math"
console.log("2π = " + math.sum(math.pi, math.pi))
// otherApp.js
import { sum, pi } from "lib/math"
console.log("2π = " + sum(pi, pi))
Vittorio Maniezzo – University of Bologna
35
Classi
Più intuitive, stile OOP senza necessitare di librerie.
class Shape
{ constructor (id, x, y)
{ this.id = id;
this.move(x, y);
}
move (x, y)
{ this.x = x;
this.y = y;
}
}
Vittorio Maniezzo – University of Bologna
36
18