Schede

Corso Javascript

JavaScript è un linguaggio di programmazione

utilizzato comunemente come parte dell'esperienza di navigazione, permette di creare interazioni con l'utente, controllare la navigazione, gestire la comunicazione asincrona, e modificare il contenuto del documento.

___Fonte: https://en.wikipedia.org/wiki/JavaScript___

ruolo di js nel web design

  • Html: contenuto
  • Css: presentazione
  • Js: comportamento

Risorse disponibili online

Hello, World

Hello, World! nel browser

alert('Hello, World!')

Hello, World! nel terminale

console.log('Hello, World!')

Esecuzione del codice

  • Interpretazione in una pagina web
  • Interpretazione in una console del browser
  • Interpretazione in terminale (node.js)

Javascript incorporato in una pagina html

<!doctype html>
<html>
    <head></head>
    <body>
        <script>
            alert('Hello world')
        </script>
    </body>
</html>

Javascript collegato ad una pagina html

<!doctype html>
<html>
    <head></head>
    <body>
        <script src="esempio.js"></script>
    </body>
</html>
// file esempio.js
alert('Hello world')

Come mostrare a video i dati

Strutture del linguaggio

JavaScript è CASE SENSITIVE

Terminare le istruzioni con punto e virgola (;)

  • E' possibile l'uso del carattere (;) per la separazione di frasi, si può omettere se queste si trovano su linee differenti (non fatelo!)
  • Gli interpreti di JavaScript trattano i fine linea come fine istruzione, se la istruzione successiva non può interpretarsi come continuazione della precedente.

Convenzioni di naming:

  • CamelCase,
  • camelCase,
  • snake_case

Identificatori

Gli identificatori in javascript cominciano con

  • una lettera,
  • una underline (_),
  • un carattere di dollaro ($);

seguito da

  • lettere,
  • numeri,
  • underline,
  • e caratteri di dollaro

Per esempio

var contatore;
var _indice;
var $indice;
var $__$__$;

Parole chiave riservate

- - - -
abstract else instanceof super
boolean enum int switch
break export interface synchronized
byte extends let this
case false long throw
catch final native throws
char finally new transient
class float null true
const for package try
continue function private typeof
debugger goto protected var
default if public void
delete implements return volatile
do import short while
double in static with

instanceof

Verifica se un oggetto è instanza di qualche prototipo.

typeof

Ritorna una stringa indicante il tipo di dato che ha una variabile. esempio

delete

Operatore che rimuove proprietà di un oggetto.

use strict

Direttiva per l'interprete di JavaScript, che indica l'uso del modo strict.

const

Parola chiave per la dichiarazione di una costante. esempio

var, let

Parola chiave per la dichiarazione di una variabile.

Variabili

  • identificatore e visibilità (scope)
  • dichiarazione e inizializzazione di variabili
  • esempi

operatori

Commenti

Esistono due tipi di commenti:

//  commento su una riga

//puoi usarlo per commentare un'istruzione:
var a = 5; //assegno la variabile

/* 
    commento
    su diverse
    righe 
*/

Literals - Letterali (valori letterali per i tipi di dato)

tipo esempio
Numeri interi 192
Numeri float 1.4
Stringhe di testo "Hello World!", 'Hello World!'
Valori logici true, false
espressioni regolari /[A-Za-z]/
Valore nullo null
Valore undefined undefined

Strutture del linguaggio

Costrutti di controllo del flusso

Costrutti di iterazione (cicli)

Tipi di dato

Boolean

  • Boolean è la rappresentazione di tipo oggetto di una variabile logica.
  • Booleans
    • operazioni logiche
    • comparazione tra numeri e valori booleani
    • undefined e null
    • Boolean() verifica se un'espressione è booleana

Per esempio

//Valori logici
var a=true
var b=false

Sono valori falsi i seguenti:

undefined
null
0
-0
NaN
''

Altri esempi

Number

Number è la rappresentazione di tipo oggetto di un tipo numerico.

JS numbers

  • i numeri in JS sono SEMPRE float a 64-bit
  • il numero massimo di decimali è 17 e la virgola mobile non è sempre accurata
  • il prefisso 0x permette di usare i numeri esadecimali
  • In JS esiste Infinity e -Infinity
  • NaN not a number: p.es. operazioni aritmetiche con le stringhe restituiscono NaN
  • proprietà e metodi principali
    • Number()
    • parseFloat()
    • parseInt()
    • toString()
    • toFixed()
    • toPrecision()
    • valueOf()

Per esempio:

  12 // numero intero in base decimale.
0345 // numero intero in base ottale.
0xFF // numero intero in base esadecimale.

3.141592654 // numero decimale.
.234955     // numero decimale.
6.023e23    // numero decimale in notazione esponenziale.

Math Object

Per lavorare con i Number, puoi usare Math che è l'oggetto che concentra molte constanti e funzioni matematiche.


String

String è la rappresentazione di tipo oggetto di una stringa.

valore nullo e valore undefined

Rappresentano l'assenza di un valore in una variabile o nel ritorno di una function.

var a=null
var b=undefined

Funzioni

Le funzioni se dichiarano con la parola riservata funzione.

function f(x,y){
    return x+y
}

Date Object

  • Date è l'oggetto utilizzato per la rappresentazione di date.
  • Internamente, questa rappresentazione è un numero che rappresenta i millisecondi trascorsi dalla data: 1 di gennaio del 1970.
  • mostrare le date
  • creare l'oggetto Date()
  • formati e metodi per le date
  • metodi get e metodi set

codice esempio

es data

Array


Objects

Timers

Sono funzioni invocate dopo un tempo determinato.

funzione significato
setTimeout() Pianifica la invocazione dopo un tempo determinato
setInterval() Pianifica l'invocazione dopo un intervallo di tempo
clearTimeout() Resetta i timer
clearInterval() Resetta i timer

Per esempio

setTimeout(function(){
    alert('asdf')
    }, 10000);

setInterval(function(){
    alert('asdf')
    }, 10000);

Ricapitolando

  • Convenzioni del linguaggio e dialogs
  • Variabili
  • Operatori
  • Costrutti condizionali e iterativi
  • Tipi primitivi
  • Tipi reference
  • Booleans
  • Function
  • Number
  • String
  • Array
  • Object
  • Timers

JavaScript nel browser

BOM- Browser Object Model - Window Object

  • BOM (Gli oggetti del browser)
  • DOM (Attraversamento e manipolazione)
  • Eventi (tipologia e gestione)
  • AJAX (interazione asincrona)
  • JSON (formato di interscambio dati)
  • L'oggetto Window è il più alto livello di oggetti JavaScript che corrispondono alla finestra del browser.
  • Window fornisce funzioni per finestre di dialogo.

Funzioni per dialog

  • alert(messaggio)
  • res=confirm(messaggio)
  • res=prompt(messaggio, valore_default)

API Window

oggetto JS descrizione
location array oggetto che rappresenta la url attuale.
history back - forward - go
navigator
screen fornisce informazione relativa al browser e alla risoluzione.

DOM

  • DOM (Document Object Model), è una interfaccia di programmazione per documenti in HTML e XML.
  • Fornisce una rappresentazione strutturata del documento (in forma di una struttura di albero), e definisce un modo per accedervi,
  • Inoltre può modificarne stile e contenuto.
  • DOM permette un accesso alla struttura di una pagina HTML mediante la mappatura degli elementi di questa pagina in un albero di nodi.
  • Ogni elemento se converte in un nodo e ogni porzione di testo in un nodo di testo.

API DOM

  • La manipolazione del contenuto nel browser dipende da un congiunto di funzioni e attributi che son provisti per l'oggetto document, che è di tipo HTMLDocument.
  • Rappresentazione di un documento HTML
  • Notazione di navigazione
  • Gerarchia di classi DOM
  • Fonte: http://stackoverflow.com
  • Maggiori informazioni: http://www.javascriptkit.com/domref/

Selezionare elementi - Selettori (I)

Sono disponibili molti metodi di selezione di elementi.

  • document.getElementById(id)
  • document.getElementsByName(name)
  • document.getElementsByTagName(tagname)
  • document.getElementByClassName(classname)

Selettori (II)

Addizionalmente ci sono selettori di tipo CSS.

  • document.querySelector(selector)
  • document.querySelectorAll(selector)

Attraversare il DOM - Traversing

Una volta stabilito un punto di partenza, si può percorrere la ramificazione

  • parentNode
  • childNodes
  • firstChild
  • lastChild
  • nextSibling
  • previousSibling

Tipi di nodi

i nodi hanno alcune proprietà che si possono consultare, per vederne le caratteristiche.

  • nodeType
  • nodeValue
  • nodeName

Traversing (II)

  • children
  • firstElementChild
  • lastElementChild
  • nextElementSibling
  • previousElementSibling
  • childElementCount

Manipolare elementi del DOM

Una volta visti i metodi per selezione e introspezione, vediamo come manipolare il DOM.

Attributi

Sono disponibili metodi specifici per l'accesso agli attributi di un elemento.

  • getAttribute()
  • setAttribute()
  • hasAttribute()
  • removeAttribute()

Contenuti (I)

Sono disponibili metodi per la manipolazione del contenuto.

  • innerHTML
  • outerHTML
  • insertAdjacentHTML()
  • beforebegin()
  • afterbegin()
  • beforeend()
  • afterend()

Contenuti (II)

per accedere al contenuto di un elemento, esistono due metodi

  • textContext, per HTMLElement
  • data, per Node

Creazione di nodi

Sono disponibili tre metodi per la creazione di nuovi nodi.

  • createElement()
  • createTextNode()
  • cloneNode()

Manipolazione di elementi

Ci sono metodi per la manipolazione di nodi dell'albero.

  • appendChild()
  • insertBefore()
  • removeChild()
  • replaceChild()

Posizionamento (I)

Sono disponibili vari metodi utili per conoscere le posizioni degli elementi, E le loro dimensioni.

  • w.pageXOffset
  • w.pageYOffset
  • w.innerWidth
  • w.innerHeight
  • getBoundingClientRect()
  • document.elementFromPoint(x,y)
  • scrollTo(x,y)
  • scrollBy(x,y)
  • scrollIntoView(x,y)

Gestione dei Form HTML

  • I moduli html si possono accedere come qualsiasi altro elemento
  • Inoltre esiste il parametro document.forms che permette di accedere attraverso gli attributi name e id
  • Per accedere agli elementi del form, si utilizza la variabile 'elements'.
  • document.forms.name.element.input

Stili

  • Per la modifica di proprietà CSS, si usa la propietà 'style'.
  • Inoltre è possibile strutturare un documento in modo che scambiarsi delle classi.
  • Questi riflettono cambi nella presentazione di documenti.
  • document.querySelector('selector').style

Eventi

Un evento è qualcosa che scatena una azione specifica nel browser.

Un evento accade quando:

  • Termina il caricamento di un elemento della pagina.

  • L'utente esegue azioni col mouse o la tastiera.

  • Eventi associati ad una pagina

    • Device-dependent input events
    • Tastiera, mouse, dispositivi Touch
    • Device-independent input events
    • Click
    • User interface events
    • Fuoco, cambi, submit
    • State-change events
    • Cambio di stato in generale
    • API-specific events
    • DnD, Players
    • Timers and error handlers
    • Temporizzatori, errori

Cattura di eventi

Sono disponibili due metodi per registrare eventi.

b.onclick=function(){console.log('asdf')};
b.addEventListener('click',function(){
    console.log('asd')
},false);

Tipologia di Eventi Javascript

EVENTO DESCRIZIONE
blur, focus Inviati ad un elemento quando rispettivamente perde il focus od ottiene il focus.
focusin, focusout Inviato ad un elemento se esso o un suo discendente rispettivamente ottiene o perde il focus
load Inviato ad un elemento quando esso e tutti i suo discendenti sono stati completamente caricati
resize Inviato all'elemento windows quando la finestra del browser ha cambiato dimensioni
scroll Inviato ad un elemento quando l'utente ha effettuato lo scroll in un differente punto dell'elemento stesso
unload Inviato all'oggetto window quando l'utente naviga fuori dalla pagina
(chiusura del browser, click su un link, a volte anche il semplice refresh)
click, dbclick Inviati ad un elemento quando il mouse è sopra di esso e viene effettuato un click o un doppio click
mousedown, mouseup Inviati ad un elemento quando il mouse è sopra di esso e viene rispettivamente premuto o rilasciato il bottone del mouse
mouseover, mouseout, mousemove Eventi inviati all'elemento in cui il puntatore del mouse entra (mouseover), in cui esce (mouseout) o in cui si sta mouvendo (mousemove)
keydown,keypress, keyup Eventi inviati quando un tasto viene premuto (keydown) è stato rilasciato (keyup) o è stato premuto (keypress)
select Inviato ad un elemento quando viene selezionato del test all'interno di esso.
change Evento inviato ad un elemento che ha cambiato il proprio valore.
submit Evento inviato quando l'utente tenta di fare il submit di un form

Maggiori informazioni: http://www.quirksmode.org/js/events_mouse.html

Ajax

AJAX (Asynchronous JavaScript And XML), è una tecnica di sviluppo web per creare applicazioni interattive. Con AJAX è possibile realizzare cambi sulle pagine senza necesità di recaricarle completamente, migliorando la interattività, velocità e usabilità nelle applicazioni.

Fonte: https://en.wikipedia.org/wiki/AJAX

Esempio

var ajax=new XMLHttpRequest()
ajax.open('get',url)
ajax.onload=function(){}
ajax.send()

JSON

  • JSON, acronimo di JavaScript Object Notation, è un formato leggero per lo scambio di dati.
  • JSON è un sottotipo della notazione literal di oggetti di JavaScript che non richiede l'uso di XML.
  • Fonte: https://en.wikipedia.org/wiki/JSON

Oggetti JS e oggetti JSON

  • Sono disponibili due metodi per la transformazione tra JSON e Oggetti di JavaScript.

  • JSON.stringify(obj) Oggetto -> JSON

  • Ritorna una stringa in formato JSON corrispondente ad un valore specificato.

  • JSON.parse(obj) JSON -> Oggetto

  • Interpreta una stringa in formato JSON e ritorna il suo oggetto corrispondente.

Per esempio

{"menu": {
        "id": "file",
        "value": "File",
        "popup": {
            "menuitem": [
                {"value": "New", "onclick": "CreateNew()"},
                {"value": "Open", "onclick": "Open()"},
                {"value": "Close", "onclick": "Close()"}
            ]
        }
    }
}

Hoisting

  • Le variabili in JavaScript hanno ambito di funzione
  • questo significa che tutte le variabili dichiarate in una funzione sono visibili nel corpo della funzione
  • Anche prima di essere dichiarate.

Esempi

var a='asdf';
(function b(){
    console.log(a)
})()// asdf
var a='asdf';
(function b(){
    console.log(a)
    var a='qwer'
})()// undefined

Jquery

Jquery è un Framework

  • write less, do more

Jquery è un Framework (una collezione o libreria di codice che agevola la risoluzione di una classe di problemi) che permette di interagire , con semplicità e rapidità, sul DOM ( Document Object Model) * di una pagina HTML

PRINCIPALI CARATTERISTICHE

  • Cross browser ( supportato dai principali browser)
  • Grande community = Grande disponibilità di plugin
  • Leggero (opinabile...)
  • Documentazione chiara e completa
  • Semplice
  • Utilizza selettori CSS (anche Css3 )
  • Sintassi compatta, permette di ridurre la quantità di codice necessario rispetto all'uso di Javascript
  • Può gestire tutti gli elementi che compongono una pagina web ( div, immagini, span, p ... )

Utilizziamo la libreria javascript jQuery per:

  • Partenza del codice quando il documento (il DOM) è pronto
  • Selezionare gli elementi
    • selettori supportati: CSS2, CSS3, custom
  • Accedere e modificare le classi CSS
  • Gestire gli stili CSS
  • Aggiungere e rimuovere contenuto e inserire elementi
  • Ottenere l'elemento html
  • Ottenere il testo contenuto nell'elemento
  • Cambiare l'HTML e/o il testo contenuto
  • Aggiungere nuovo contenuto ad un elemento esistente
  • Gestire gli eventi
  • Mostrare e nascondere elementi
  • Aggiungere animazioni ed effetti
  • Gestire le chiamate asincrone (AJAX)
  • Creare e processare dati inJSON

Partenza del codice quando il documento (il DOM) è pronto

$(document).ready(function() {
//codice da eseguire al caricamento del documento
});

INCLUDERE JQUERY NELLE PAGINE WEB

  1. Scarichiamo l'ultima versione di Jquery dal sito http://jquery.com/ il file avrà un nome nella forma jquery-x.x.-min.js
  2. Per usarlo nelle nostre pagine web dobbiamo linkarlo attraverso il comando <script>...</script> nella sezione <head /> della nostra pagina web
<html>
<head>
<script src="percorso/al/file/jquery-x.x.js"></script>
</head>
<body> ... </body>
</html>

"Filosofia Jquery"

//Cerca questo elemento
$("p")
//Fai questa azione
.html("Hello World");
<html>
<head>
<script src="percorso/jquery.js"></script>
<script type="javascript/text">
$(document).ready(function(){
$("p").html("Hello World");
}
</script>
</head>
<body>
<div>
<p></p>
</div>
</body>
</html>

Selezionare gli elementi

La principale caratteristica della funzione jQuery() (abbreviata in $() ) è quella di selezionare elementi HTML per modificarli: basta passare un parametro stringa (tra apici doppi ["] o singoli ['] ) come negli esempi che seguono:

$("div");
$("#mioId");
$(".miaClasse");
$("p#mioId");
$("ul li a.nav");

selettori css 2 / css 3

jQuery supporta tutti i selettori anche quelli avanzati e quelli del CSS3

$("p > a");
$("input[type=text]");
$("a:first");
$("p:odd");
$("li:first-child");

jQuery supporta poi alcuni selettori custom:

$(":animated");
$(":button"); selects any button elements (inputs or buttons)
$(":radio");
$(":checkbox"); selects checkboxes
$(":checked");
$(":header"); selects header elements (h1, h2, h3, etc.)

Accedere e modificare le classi CSS

Con jQuery è facile aggiungere, scambiare o rimuovere classi CSS: ecco i tre metodi

//aggiunge la classe "content" da tutti i <div>
$("div").addClass("content");
//rimuove la classe "content" da tutti i <div>
$("div").removeClass("content"); 
//fa lo switch della classe "content" da tutti i <div>
$("div").toggleClass("content");

Se un elemento è di una determinata classe allora esegui il codice:

if ($("#mioElemento").hasClass("content")) {
    //codice
}

Gestire gli stili Css con Jquery

Ecco come modificare i css con jQuery:

$("p").css("width", "400px");
$("#mioElemento").css("color", "blue");
$("ul").css("border", "solid 1px #ccc");

Aggiungere e rimuovere contenuto e inserire elementi

Ottenere l'elemento html

var mioElementHTMLo = $("#mioElemento").html();

Ottenere solo il testo contenuto nel tag

var mioElementHTMLo = $("#mioElemento").text();

Cambiare l'HTML e/o il Testo

$("#mioElemento").html("<p>Questo è il nuovo contenuto</p>");
$("#mioElemento").text("Questo è il nuovo contenuto."); // questo sostituisce il testo presente

Far seguire (appendere) del contenuto ad un elemento

$("#mioElemento").append("<p>Questo lo aggiungo.</p>");
$("p").append("<p>Questo pure.</p>"); // Aggiunge questo contenuto ad ogni paragrafo

Altri comandi

    appendTo()
    prepend()
    prependTo()
    before()
    insertBefore()
    after()
    insertAfter()
  • lavorano in modo simile con specifiche peculiarità
  • Ulteriori informazioni jQuery.com

Gli Eventi: intercettare il click del mouse con jQuery

$("a").click(function() {
// il codice presente viene eseguito onclick!
});
  • Il codice dentro function() viene eseguito quando un link viene cliccato

  • Altri comuni eventi inclusi in jQuery

    • blur()
    • focus()
    • hover()
    • keydown()
    • load()
    • mousemove()
    • resize()
    • scroll()
    • submit()
    • select()

Mostrare e nascondere elementi con jQuery

$("#mioElemento").hide("slow", function() {
// nasconde
}

//mostra
$("#mioElemento").show("fast", function() {
// qui dentro viene eseguito una volta che l'elemento è stato mostrato
}

// scambia: se è nascosto mostra e se è visibile nasconde
$("#mioElemento").toggle(1000, function() {
}
    $("#mioElemento").fadeOut("slow", function() {
        //fai qualcosa quando termina l'effetto
    }


    $("#mioElemento").fadeIn("fast", function() {
        //fai qualcosa quando termina l'effetto
    }
    $("#mioElemento").fadeTo(2000, 0.4, function() {
        //fai qualcosa quando termina l'effetto
    }
    $("#mioElemento").slideDown("fast", function() {
        //fai qualcosa quando termina l'effetto
    }


    $("#mioElemento").slideUp("slow", function() {
        //fai qualcosa quando termina l'effetto
    }

    $("#mioElemento").slideToggle(1000, function() {
        //fai qualcosa quando termina l'effetto
    }

Animate

    $("#mioElemento").animate(
    {
    opacity: .3,
    width: "500px",
    height: "700px"
    }, 2000, function() {
    // fai qualcosa quando termina l'animazione
    }
    );

Oggetto jQuery() $()

  • jQuery() oppure $() Permette di selezionare e creare elementi del DOM Può avere come parametro:
  • Selettore CSS $("p.evidenziato") Restituisce un array di oggetti, eventualmente vuoto
  • Oggetti javascript $(this.value) Restituisce un array di oggetti contenente l’elemento passato come parametro
  • Codice HTML $("Ciao Mondo") Crea un elemento del DOM e restituisce un array di oggetti contenente l’elemento appena creato

Selettori TAG HTML

$(elemento)
  • selezionare gli elementi HTML passati come parametro
    • $("a") tutti i link (e ancore) della pagina
    • $("p") tutti i paragrafi della pagina
    • $("a,p") tutti i link e i paragrafi della pagina

Selettori di ID

  • Permette di selezionare l’elemento della pagina che ha l’id passato come parametro
  • $(#idelemento) elemento della pagina con attributo id="principale"
  • $("div#principale") div della pagina con attributo id="principale"
  • $("#principale") Essendo l’id univoco all’interno della pagina la selezione del div poteva essere omessa

Selettori di CLASSE

  • $(.nomeclasse) Per selezionare gli elementi della pagina che hanno la classe passata come parametro
  • $(".evidenziato") Elementi della pagina che hanno classe evidenziato
  • $("div.evidenziato") tutti i div della pagina con classe evidenziato

Selettori per ATTRIBUTI

selettore descrizione
$(elemento[attributo]) elementi della pagina che hanno l’attributo passato come parametro
$(elemento[attributo=x]) elementi della pagina che hanno l’attributo passato come parametro uguale al valore x
$(elemento[attributoˆ=x]) elementi della pagina che hanno l’attributo passato come parametro che inizia per x
$(elemento[attributo$=x]) elementi della pagina che hanno l’attributo passato come parametro che finisce per x
$(elemento[attributo*=x]) elementi della pagina che hanno l’attributo passato come parametro che contiene la stringa x
$("input[value]") elementi input in cui è specificato l’attributo value
$("input[type=‘radio’]") elementi input di tipo radio
$("a[hrefˆ=‘http://’]") i link con indirizzo non relativo
$("a[href*='it.wikipedia.org']") i link che contengono nell’indirizzo la stringa ‘it.wikipedia.org’
$("a[href$='.pdf']") i link a file pdf
$("img[title]") elementi img in cui è specificato l’attributo title
$("img[title=‘logo’]") le immagini in cui l’attributo titolo è uguale a ‘logo’
$("img[src$='.png']") le immagini con estensione png
$("img[title^='logo']") le immagini in cui l’attributo titolo inizia con ‘logo’
$("img[title*='logo']") le immagini in cui l’attributo titolo contiene la stringa ‘logo’

Selettori GERARCHICI

selettore descrizione
$(padre > figli) elementi "figli" che sono discendenti diretti dell’elemento "padre"
$(fratello+sorelle)
$(".A + .B") Permette di selezionare gli elementi "sorelle" che sono direttamente preceduti da un elemento "fratello"
$(fratello~sorelle)
$(".A ~ .B") Permette di selezionare gli elementi "sorelle" che sono preceduti da un elemento "fratello"
$(padri:has(discendenti)) Permette di selezionare gli elementi "padri" che hanno almeno un "discendente" passato come parametro
$("ul:has(a)") tutti gli ul che hanno come discendente almeno un link
$("div:has(img)") tutti i div che hanno comediscendente almeno un’immagine
$(div > li) errato!!! Selezionerebbe tutti gli elementi di una lista contenuti direttamente in un div.

Selettori di Posizione

selettore descrizione
Questi selettori sono zero-based utilizzano come indice iniziale lo 0
$(:first) $(:last) Permettono di selezionare il primo (:first) e ultimo (:last) elemento di un insieme il primo link della pagina
$("p.evidenziato:first") il primo paragrafo con class "evidenziato"
$("img[src*=logo]:last") ultima immagine che contenga nell’indirizzo la parola logo
$(:first-child) $(:last-child) Per selezionare il primo (:first-child) e l’ultimo (:last-child) elemento discendente
$("p.evidenziato:first-child") Per selezionare il primo elemento contenuto in ogni paragrafo con class "evidenziato"
$("li:last-child") Per selezionare l'ultimo elemento contenuto in ogni li
$("div:first-child") Per selezionare il primo elemento contenuto in ogni div
$(:even) $(:odd) Permettono di selezionare gli elementi in posizioni pari (:even) e dispari (:odd)
$("li:odd") i list item di posizione dispari
$("table.zebra tr:even") le righe in posizione pari delle tabelle che hanno class "zebra"

Selettori Cardinali di Posizione

  • $(:nth-child(n)) e $(:nth-child(even|odd)) Permettono di selezionare gli elementi discendenti in posizioni uguale a n
selettore descrizione
$("tr:nth-child(4)") il quarto elemento contenuto in ogni tr
$("tr:nth-child(even)") gli elementi in posizione pari in ogni tr
$("tr:nth-child(odd)") dispari in ogni tr gli elementi in posizione
  • Questi selettori sono zero-based: utilizzano come indice iniziale lo 0
  • $(:eq(n)), $(:lt(n)) e $(:gt(n)) Permettono di selezionare gli elementi in posizioni uguale, maggiore o minore di n
selettore descrizione
$("tr:eq(4)") il quinto elemento tr
$("tr:lt(4)") i primi cinque tr
$("tr:gt(4)") dal sesto tr in poi

Selettori Custom

selettore descrizione
:button seleziona tutti i bottoni
:checkbox seleziona tutte le checkbox
:radio seleziona tutti i radio button
:checked seleziona le check box e i radio button che sono selezionati
:disabled, :enabled elementi di input disabilitati o abilitati
$("li:not(.evidenziato)") gli elementi li che non hanno classe evidenziato
:hidden elementi nascosti
:visible elementi visisbili
:text seleziona textbox
:filter(selettore) applica un ulteriore selettore all'insieme selezionato
:contains(cerca) seleziona gli elementi che contengono il testo "cerca"

Operazione sugli oggetti selezionati/creati

Navigazione del DOM

$(selettore).children([selettore]) figli diretti dell'insieme selezionato $(selettore).next() elemento successivo a quello selezionato $(selettore).parent([selettore]) padre dell'elemento selezionato $(selettore).parents([selettore]) $(selettore).find(selettore)

Operazione sugli oggetti selezionati/creati

Manipolazione del DOM metodi disponibili
Inserire elementi after, append, before, prepend, html, text, wrap, clone, value
Cancellare elementi empty, remove, removeAttr
Modifica elementi attr, addClass, removeClass, toggleClass, css, hide, show, toggle

Operazione sugli oggetti selezionati/creati

  • Esempi Manipolazione del DOM
$("li").text("testo lista").insertAfter("li:first");
//inserisce un elemento li appena creato dopo il primo li del documento

$("div#principale").append("dentro il div");
//inserisce un paragrafo dentro il div che ha id principale

$("input#email").val()
//valore della input box con id email

$("span").wrap("div")
//crea un div che contiene tutti gli elementi span della pagina

$("p.evidenziato").text("Sono evidenziato");
//imposta il testo dei paragrafi di classe evidenziano con la
stringa passata come parametro

$("img.logo").css("border","solid orange 3px");
//cambia lo stile a tutte le immagini di classe logo
  • Permette di scorrere il vettore di elementi selezionati e di eseguire una funzione per ogni elemento
$(selettore).each()
$(img).each(function(i){
    $(this).attr("alt","immagine "+i);
})

Operazione sugli oggetti selezionati/creati

  • Concatenazione operazioni

  • E' possibile concatenare più azioni su uno stesso selettore,

  • se le operazioni precedenti non alterano l'insieme di oggetti restituiti dal selettore.

  • nasconde tutti gli elementi di classe invisibile e aggiunge la classe sparito

$(.invisibile).hide().addClass("sparito")

  • crea un immagine con attributo src="img/test.jpg", di classe logo e la appende al div con id principale

$("").attr("src","img/test.jpg").addClass("logo").appendTo("div#principale")

Operazione sugli oggetti selezionati/creati

  • Concatenazione Avanzata .end()
  • NB: alcune funzioni alterano l'insiemi di oggetti restituiti dal selettore
selettore descrizione
$(div p:first) Seleziona il primo paragrafo di ogni DIV
.addClass("primoParagrafo") Aggiunge la classe primoParagrafo
.find("a:first") Seleziona il primo link del primo Paragrafo di ogni div
.text("primo link") Modifica il testo in "primo link"
Ritorna alla selezione precedente (primo
.css("border","solid 5px"); Modifica lo stile del bordo

Eventi supportati

  • dblclick
  • load
  • unload
  • submit
  • focus
  • blur
  • change
  • select
  • resize
  • keydown
  • keypress
  • keyup
  • scroll
  • mousemove
  • mousedown
  • mouseup
  • mouseover
  • error

Tipologia di Eventi Javascript

EVENTO DESCRIZIONE
blur, focus Inviati ad un elemento quando rispettivamente perde il focus od ottiene il focus.
focusin, focusout Inviato ad un elemento se esso o un suo discendente rispettivamente ottiene o perde il focus
load Inviato ad un elemento quando esso e tutti i suo discendenti sono stati completamente caricati
resize Inviato all'elemento windows quando la finestra del browser ha cambiato dimensioni
scroll Inviato ad un elemento quando l'utente ha effettuato lo scroll in un differente punto dell'elemento stesso
unload Inviato all'oggetto window quando l'utente naviga fuori dalla pagina (chiusura del browser, click su un link, a volte anche il semplice refresh)
click, dbclick Inviati ad un elemento quando il mouse è sopra di esso e viene effettuato un click o un doppio click
mousedown, mouseup Inviati ad un elemento quando il mouse è sopra di esso e viene rispettivamente premuto o rilasciato il bottone del mouse
mouseover, mouseout, mousemove Eventi inviati all'elemento in cui il puntatore del mouse entre (mouseover), in cui esce (mouseout) o in cui si sta mouvendo (mousemove)
keydown,keypress, keyup Eventi inviati quando un tasto viene premuto (keydown) è stato rilasciato (keyup) o è stato premuto (keypress)
select Inviato ad un elemento quando viene selezionato del test all'interno di esso.
change Evento inviato ad un elemento che ha cambiato il proprio valore.
submit Evento inviato quando l'utente tenta di fare il submit di un form

on

$(selettore).on(evento,[dati],function(evento){...})

Permette di collegare gli eventi ad un selettore e di eseguire la funzione associata

$(":text").on('focusin', function(){
this.addClass('inserimento');
}).on('focusout',function(){
this.removeClass('inserimento');
})

Per ogni casella di testo aggiunge la classe inserimento quando il focus è sull'oggetto e rimuove la stessa classe quando il focus non è più dell'oggetto

Sintassi abbreviata eventi

  • $(selettore).on(evento,[dati],function(evento){...})
  • $(selettore).evento([dati],function(evento){...})
    //nasconde i listitem al click su di essi
$("li").click(function(){$(this).hide()});

$("#mostraNascosti").mouseover(function(){
    //quando il mouse passa sopra l'elemento con id="mostraNascondi" gli elementi li nascosti vengano visualizzati
$("li:hidden").show();
});

//esempio passaggio dati alle funzioni di callback degli eventi
var messaggio="ciao mondo"
$("li").click({msg:messaggio},function(evento){
alert(evento.data.msg)
});

Proprietà Oggetto evento

Le funzioni di callback (richiamate al verificarsi di ogni evento) hanno come parametro un oggetto che descrive l'evento occorso.

proprietà Descrizione
.currentTarget Elemento del DOM che ha rilanciato l'evento
.data I dati opzionali passati dalla funzione on
.pageX Ascissa della posizione del mouse
.pageY Ordinata della posizione del mouse
.target Elemento del DOM in cui è stato generato l'evento
.timeStamp Quando si è verificato un evento (millisecondi passati dal 1 gennaio 1970)
.type Descrive la natura dell'evento
.which Nel caso di eventi scatenati da mouse o tastiera indica (in codice) quale bottone o tasto è stato premuto.
.keyCode Per avere informazioni sul carattere inserito si utilizza

Funzioni Oggetto evento

L'oggetto evento offre alcuni utili metodi Metodo Descrizione

  • .preventDefault() Non fa eseguire la funzione di default legata all'evento.

Es. disattivare tutti i link di una pagina:

$("a").on('click',function(evento){
evento.preventDefault();
});
  • .stopPropagation() Impedisce l'inoltro dell'evento ad ogni elemento padre
  • .stopImmediatePropagation() Impedisce l'inoltro dell'evento ad ogni altro elemento del DOM

Lanciare eventi

E' possibile tramite jQuery lanciare eventi, sia standard che personalizzati $(selettore).trigger(evento, [dati])

  • Esempio: $("a#link").trigger('click') invia un click all'ancora con id uguale a link

  • Sintassi abbreviata $(selettore).evento([dati])

  • Esempio $("a#link").click()


by Emiliano Castellina is licensed under a Creative Commons Attribuzione Non commerciale
Condividi allo stesso modo 3.0 Unported License.

Esempi Jquery

SELETTORI

I Selettori in jquery permettono di prendere il controllo di uno o più oggetti di una pagina web, per seleziona un elemento si usa la funzione $ a cui viene passato un "qualcosa", qui sotto alcuni esempi di Selettori.

  • Selettore di ID => $("#blocco")
  • Selettore di Classe => $(".elenco")
  • Selettore tramite nome TAG => $("p")
  • Selettore tramite attributi => $("[title*= titolo]")
<body>
<div id="blocco">  <!-- $('#blocco') -->
<p><strong>ELENCO:</strong> III C </p> $("strong") $("p strong")
<ul class="elenco"> <!-- $('.elenco') -->
<li>PAOLO</li>
<li>PIETRO</li>
<li>CARLO</li>
<li>YASMINE</li>
</ul>
<strong>Fine elenco</strong> $("strong")
</div>
</body>

FILTRI

I filtri permettono di ottenere una maggiore precisione nella selezione degli elementi fatta con i selettori

  • Filtri semplici (Basic Filter)

    • :first
    • :last
    • :not()
    • :eq()
  • Filtri sul contenuto ( Content Filter)

    • :empty
    • :contains(text)
    • :has(selector)
  • Filtri sugli attributi ( Attribute )

    • [attribute]
    • [attribute=value]
    • [attribute!=value]
  • Filtri sugli elementi dei form ( Form )

    • :input
    • :text
    • :submit
    • :disabled
    • :checked

FILTRI SU TABELLE

Cognome Provincia #
MAURO TO presente
PAOLO TO assente
CARLO MI presente
PIETRO MI presente
YASMINE RM assente
  • $("th").css("background-color", "#9bbb59");
  • $("tr:odd").css ("background-color", "#dee7d1");
  • $("tr:even").css ("background-color", "#eff3ea");
  • $( "td:contains('assente')" ).css('color','red');
  • $( "td[align=left]").css('text-align','center');

FILTRI SU MODULI

checkbox

<form name="nome_form" id="id_form">
<label>Colori preferiti</label>
<input type="checkbox" value="rosso" /> Rosso
<input type="checkbox" value="giallo" /> Giallo
<input type="checkbox" value="blu" /> Blu
<input type="button" value="sono selezionati..." onclick="dammi_selezionati()" />
</form>

<script type="text/javascript">
function dammi_selezionati(){
	var stringa='';
	$(":checked") .each( function() {
		stringa+=" "+ $(this).val() +" ";
	});
	alert(stringa);
}
</script>

option

<form name="nome_form" id="id_form">
<label>Colori preferiti</label><br />
<select id="colori"multiple="multiple">
<option value="rosso">Rosso</option>
<option value="blu">Blu</option>
<option value="giallo">Giallo</option>
</select>
<input type="button" onclick="dammi_selezionato()"
value="Dammi selezionati">
</form>
<script type="text/javascript">
function dammi_selezionato(){
	var stringa='';
	$("#colori option:selected").each( function() {
		stringa+=" "+ $(this).val() + " ";
	});
	alert(stringa);
} ;
</script>

manipolare il DOM

Alcune funzioni che permettono di manipolare il DOM, 
per un elenco completo vedi la documentazione su
http://api.jquery.com/category/manipulation/

prepend()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno"></div>
</div>


$("h1").prepend("<span>Primo</span>");

before()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno"></div>
</div>


$("h1").before("<span>Primo</span>");

append()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno"></div>
</div>

$("h1").append("<span>Primo</span>");

after()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno"></div>
</div>

$("h1").after("<span>Primo</span>");

html()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno"></div>
</div>

$("#blocco_interno").html("<strong>Ciao , sono un testo dinamico</strong>");

addClass()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno"></div>
</div>

$("# blocco_interno).addClass("selezionata");

removeClass()

<div id="blocco">
<h1>Esempio</h1>
<div id="blocco_interno" class="selezionata">
</div>
</div>

$("#blocco_interno").removeClass("selezionata");

html() + val()

<form>
<input type="text" id="testo" name="testo" value="ciao" />
</form>
<span></span>

$("span"). html( $("#testo").val());

val()

<form>
<input type="text" id="testo" name="testo" />
</form>
<span></span>

$("#testo).val('Hello world') ;

.css()

Possiamo gestire le regole css di un elemento attraverso la funzione .css

  • sintassi: $("#elemento).css ( regola-css , valore);
  • $("#elemento").css("color", "red");
  • $("#elemento").css("height", "100px");
  • $("#elemento").css("border", "1px solid red");
  • $("#elemento").css("background-color", "#ffcc90");
//accorpare le regole in un oggetto
$("#elemento).css( {
regolaCss : "valore", //sintassi camelCase per la proprietà
regolaCss : "valore",
regolaCss : "valore" //l'ultimo lemento senza virgola
} );
//accorpare le regole in un oggetto
$("#elemento").css({ "color": "red",
"height" : "100px",
"border" : "1px solid red",
"background-color" : "#ffcc90"
});

ATTRIBUTI SET & GET

Con Jquery possiamo leggere e impostare i valori per ogni attributo del DOM, ad esempio:

  • leggere e scrivere dinamicamente dentro un elemento p
  • leggere e scrivere il contenuto di un input text
  • leggere e scrivere una proprietà CSS

GETTERS

  • .html()
  • .attr('id')
  • .val()
  • .width()

SETTERS

  • .html('<p>ciao</p>)
  • .attr('id','blocco_testo')
  • .val('ciao')
  • .width('120px')

GLI EVENTI

Con jquery possiamo intercettare alcuni eventi e dar seguito ad una operazione quando questi si verificano

Struttura di una funzione per intercettare un evento Quando su questo/i elemento/i Si verifica questo evento

$("button").click(function(){
// qualche operazione
});
<html>
<head>
<script src="percorso/jquery.js"></script>
<script style="text/javascript">
$('#pulsante').click(function(){
$('#box').slideUp()
}
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width:100px; height:100px; background-color:red"></div>
</body>
<html>

DOM ready() Eseguire una funzione solo al caricamento della pagina

<head>
<script type="text/javascript">
$(document).ready(function() {
// fai qualcosa
});
</script>
</head>
<head>
<script type="text/javascript">
$(function() {
// fai qualcosa
});
</script>
</head>

eventi legati al mouse

  • mouseover
  • mouseout
  • mousedown
  • mouseleave
  • ...
<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$('p'). mouseover (function(){
alert('Ciao, sono una finestra attivata da un evento');
});
})
</script>
</head>
<body>
<p>Passa con il mouse sopra la frase</p>
</body>
</html>

eventi legati alla pressione di tasti

<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$('#parola').keypress(function(evento){
var keycode = (evento.which ? evento.which :
evento.keyCode);
$('p').append(' '+evento.which+' '+String.fromCharCode(keycode));
});
})
</script>
</head>
<body>
<input type="text" id="parola" />
<p>Hai premuto i seguenti tasti (in codice ASCII ):<br /></p>
</body>
</html>

GLI EFFETTI

jQuery ci permettere di realizzare dei semplici effetti animati con pochissime linee di codice. http://api.jquery.com/category/effects/

Gli effetti li possiamo raggruppare in 4 tipologie

  • FadeIn / fadeOut / fadeToggle
  • Hide / Show
  • Slide up / Slide Down
  • Animate

slideUp()

<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#pulsante").click(function () {
$("#box").slideUp();
});
})
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width: 100px; height: 100px; background-color: red;"></div>
</body>
</html>

slideDown()

<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#pulsante").click(function () {
$("#box").slideDown();
});
})
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width: 100px; height: 100px; background-color: red;
display:none;"></div>
</body>
</html>

Ottenere un effetto Apri/chiudi

<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#pulsante").click(function () {
$("#box").slideToggle();
});
})
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width: 100px; height: 100px; background-color: red;"></div>
</body>
</html>

Gestire la velocità dell'animazione

<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#pulsante").click(function () {
$("#box").slideToggle(3000);
});
})
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width: 100px; height: 100px; background-color: red;"></div>
</body>
</html>

Eseguire un'azione al completamento dell'animazione

<html>
<head>
<script src="jquery.js"></script>
<script type="text/javascript">
$(function(){
$("#pulsante").click(function () {
$("#box").slideToggle(1000, function(){
alert("Animazione completata");
} );
});
})
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width: 100px; height: 100px; background-color: red;"></div>
</body>
</html>

ANIMATE

Con la funzione animate, si possono creare "transizioni" sulle proprietà css di tipo numerico di un oggetto.

<script type="text/javascript">
$(function(){
$("#pulsante").click(function () {
$('#box').animate({left: '+=500' },
1000,
function() { alert("Animazione completata"); }
);
});
}) ;
</script>
</head>
<body>
<input type="button" value="cliccami" id="pulsante" />
<div id="box" style="width: 100px; height: 100px; background-color: red;position:
relative; "></div>

Scroller di pagina

Lo scroller di pagina viene usato per spostarsi velocemente tra i contenuti di una pagina web. Un tipico esempio sono le ancore "torna su" che troviamo alla fine di un testo che permettono con un click di tornare in cima allo stesso

Scroller di pagina verticale

<script type="text/javascript">
function vai_a(id)
{
$('html,body').animate({scrollTop: $("#"+id).offset().top},1000);
}
</script>
<div id="blocco_1" class="blocco" style=" background-color: red;">
<div class="menu">
<a href="#" onclick="vai_a('blocco_1');return false;" >Vai al blocco 1</a>
<a href="#" onclick="vai_a('blocco_2');return false;" >Vai al blocco 2</a>
<a href="#" onclick="vai_a('blocco_3');return false;" >Vai al blocco 3</a>
</div>
Testo Primo Blocco 1
</div>

Scroller di pagina orizzontale

<script type="text/javascript">
function vai_a(id)
{
$('html,body').animate({ scrollLeft: : $("#"+id).offset().left},1000);
}
</script>
<div id="blocco_1" class="blocco" style=" background-color: red;">
<div class="menu">
<a href="#" onclick="vai_a('blocco_1');return false;" >Vai al blocco 1</a>
<a href="#" onclick="vai_a('blocco_2');return false;" >Vai al blocco 2</a>
<a href="#" onclick="vai_a('blocco_3');return false;" >Vai al blocco 3</a>
</div>
Testo Primo Blocco 1
</div>

SLIDER DI IMMAGINI

<script>
$(function(){
$('#blocco img:gt(0)').hide();
setInterval(function(){ $('#blocco :first-child').fadeOut(20).next('img').
fadeIn(700).end().appendTo($('#blocco'));}, 3000);
});
</script>
<style type="text/css">
.blocco{ width: 500px; height:350px; overflow: hidden;}
.blocco img{ width: 500px; height:350px; float: left;}
</style>
<div id="blocco" class="blocco">
<img src="gallery/1.jpg" />
<img src="gallery/2.jpg" />
<img src="gallery/3.jpg" />
</div>

VALIDARE i moduli

Molto utili per guidare l'utente nella compilazione e segnalare degli errori.

Implementiamo il form

<li>
<label>Nome</label>
<input type="text" id="nome" name="nome" class="obbligatorio" />
</li>
<li>
<label>Indirizzo</label>
<input type="text" id="indirizzo" name="indirizzo "/>
</li>
<li>
<label>Email</label>
<input type="text" id="email" name="email" class="obbligatorio" />
</li>
<li>
<input type="button" id="invia" name="invia" value="invia" onclick="controlla()" />
</li>

FORM VALIDATION: LOGICA

function controlla(){
$(".obbligatorio ").each( function(){
if( ($(this).val()=="") ){
errore=true;
$(this).prev().addClass('rosso');
}
else{ $(this).prev().removeClass('rosso'); }
})
if(errore==true)
{ alert("Il form contiene errore/i, si prega di correggere."); }
else
{alert("Complimenti! Non ci sono errori!"); }
}
</script>

Introduzione

Perchè una reintroduzione? Perchè  JavaScript ha la ragionevole pretesa di essere il linguaggio di programmazione più frainteso del mondo. Benchè spesso considerato ironicamente come un giocattolo, la sua ingannevole semplicità nasconde alcune potenti caratteristiche. Il 2005 vide il lancio di diverse applicazioni di alto profilo, che mostravano come la conoscenza profonda di questa tecnologia sia un importante abilità per qualunque sviluppatore web.

E' utile iniziare con un accenno alla storia del linguaggio. JavaScript fu creato nel 1995 da Brendan Eich, un ingegnere presso Netscape, e rilasciata per la prima volta con Netscape 2 all'inizio del 1996. Originariamente dove essere chiamato LiveScript, ma fu rinominato in Javacript per una fatalmente dannosa decisione di marketing che tentava di approfittare della popolarità del linguaggio Java della Sun Microsystem — nonostante abbiano molto poco in comune. Questa è stata una fonte di confusione da allora.

Microsoft rilasciò una versione più compatibile del linguaggio chiamata JScript con IE 3 alcuni mesi dopo. Netscape sottomise il linguaggio alla Ecma International, una organizzazione europea per gli standard, che risulta nella prima edizione degli standard ECMAScript nel 1997. Lo standard ricevette un significativo aggiornamento come ECMAScript edition 3 nel 1999, ed è rimasto più o meno stabile da allora. La quarta edizione fu abbandonata a causa delle differenze di vedute sulla complessità del linguaggio. Molte parti della quarta edizione formano la base del nuovo ECMAScript edizione 5, pubblicato nel dicembre del 2009.

Questa stabilità è una grande notizia per gli sviluppatori, in quanto ha dato alle varie implementazioni diverso tempo per recuperare. Ci si concentrerà quasi esclusivamente sul dialetto dell'edizione 3. Per familiarità continueremo a chiamarlo JavaScript dappertutto.

Diversamente dalla maggior parte dei linguaggi di programmazione, il linguaggio JavaScript non ha il concetto di input e output. E' stato disegnato per girare come un linguaggio di scripting in un ambiente ospite, ed è responsabilità dell'ambiente ospite di fornire meccanismi per comunicare con il mondo esterno. L'ambiente ospite più comune è il browser, ma l'interprete JavaScript può essere trovato anche in Adobe Acrobat, Photoshop, motore Widget di Yahoo! , e addirittura in ambienti lato server.

Panoramica

JavaScript è un linguaggio dinamico orientato agli oggetti; esso ha tipi e operatori, oggetti nucleo, e metodi. La sua sintassi deriva dai linguaggi Java e C, quindi molte strutture utilizzate da questi linguaggi ricorrono anche in JavaScript. Una delle differenze chiave è che JavaScript non ha classi; invece, la funzionalità di classe è realizzata dai prototipi oggetto. L'altra differenza principale è che le funzioni sono oggetti, dando alle funzioni la capacità di mantenere codice eseguibile ed essere passate in giro come ogni altro oggetto.

Cominciamo guardando il blocco di costruzione di qualsiasi linguaggio: i tipi. I programmmi JavaScript manipolano valori, e tutti quei valori appartengono ad un tipo. I tipi JavaScript sono:

... oh, e Undefined (indefiniti) e Null (nulli), che sono leggermente strani. E gli Array, che sono un tipo speciale di oggetto. E Date ed Espressioni regolari, che sono oggetti che si ottengono gratuitamente. E per essere tecnicamente precisi, le funzioni sono solo un tipo speciale di oggetto. Quindi il diagramma dei tipi somiglia più a questo:

  • Numeri
  • Stringhe
  • Booleani
  • Oggetti
    • Funzioni
    • Array
    • Date
    • ExpReg
  • Null
  • Undefined

E ci sono anche alcuni tipi nativi di Errori. Comunque, le cose sono molto più semplici se ci atteniamo al primo diagramma

Numeri

I numeri in JavaScript sono in formato 64-bit a doppia precisione valore del IEEE 754, secondo le specifiche. Questo ha qualche interessante conseguenza. Non esiste una cosa come un intero in JavaScript, quindi bisogna stare un pò attenti con la vostra aritmetica, se siete abituati alla matematica in C o Java. Stare attenti a cose come:

0.1 + 0.2 == 0.30000000000000004

In pratica, i valori interi sono trattati come int a 32-bit (e sono memorizzati in questo modo in alcune implementazioni dei browser), che può essere importante per operazioni in bit. Per dettagli, consulta La Guida Completa sui Numeri JavaScript.

Gli operatori numerici standard sono supportati, incluso addizione, sottrazione, modulo (o resto) aritmetico e così via. Vi sono anche oggetti nativi che non sono stati menzionati prima, chiamati Math per trattare funzioni matematiche più avanzate e costanti:

Math.sin(3.5);
var d = Math.PI * r * r;

E' possibile convertire una stringa in un intero utilizzando la funzione nativa parseInt(). Questo prende la base per la conversione come secondo argomento opzionale, che si dovrebbe fornire sempre:

> parseInt("123", 10)
123
> parseInt("010", 10)
10

Se non si fornisce la base, si possono ricevere risultati inattesi:

> parseInt("010")
8

Questo succede perchè la funzione parseInt ha deciso di trattare la stringa come un ottale a causa del primo 0.

Se si vuole convertire un numero binario in un intero, basta cambiare la base:

> parseInt("11", 2)
3

Similmente, è possibile analizzare numeri in virgola mobile usando la funzione nativa parseFloat() che utilizza sempre la base 10 diversamente dalla cugina parseInt().

E' inoltre possibile utilizzare l'operatore unario + per convertire valori in numeri:

> + "42"
42

Un valore speciale chiamato NaN (abbreviazione per "Not a Number" - Non un Numero) viene restituita se la stringa non è numerica:

> parseInt("hello", 10)
NaN

Il NaN è tossico: se viene fornito come input a qualsiasi operazione matematica, il risultato sarà anch'esso NaN:

> NaN + 5
NaN

E' possibile verificare se NaN usando la funzione nativa isNaN():

> isNaN(NaN)
true

Anche JavaScript ha i valori speciali Infinity-Infinity:

> 1 / 0
Infinity
> -1 / 0
-Infinity

E' possibile analizzare i valori Infinity, -Infinity e NaN usando la funzione nativa isFinite():

> isFinite(1/0)
false
> isFinite(-Infinity)
false
> isFinite(NaN)
false
Nota: Le funzioni parseInt() e parseFloat() analizzano una stringa finchè raggiungono un carattere che è non è valido per il formato numerico specificato, quindi restituiscono il numero analizzato fino a quel punto. Tuttavia l'operatore "+" converte semplicemente la stringa a NaN se è presente in essa qualche carattere invalido. E' sufficiente provare ad eseguire l'analisi della stringa "10.2abc" con ogni metodo da soli utilizzando la console e sarà possibile capire meglio le differenze.

Stringhe

Le stringhe in JavaScript sono sequenze di caratteri. Più precisamente, sono sequenze di Caratteri Unicode, con ogni carattere rappresentato da un numero a 16-bit. Questa dovrebbe essere una buona notizia per tutti coloro che hanno avuto a che fare con l'internazionalizzazione.

Se si vuole rappresentare un singolo carattere, occorre semprlicemente utilizzare una stringa di lunghezza 1.

Per trovare la lunghezza di una stringa, accedere la sua proprietà length:

> "hello".length
5

Ecco il nostro primo assaggio degli oggetti JavaScript! E' stato menzionato che le stringhe sono anch'esse oggetti? Ed hanno anche metodi:

> "hello".charAt(0)
h
> "hello, world".replace("hello", "goodbye")
goodbye, world
> "hello".toUpperCase()
HELLO

Altri tipi

JavaScript distingue tra null, che è un oggetto di tipo 'object' che indica un mancanza deliberata di valore, e undefined, che è un oggetto di tipo 'undefined' che indica un valore non inizializzato — ossia un valore che non è stato ancora assegnato. Parleremo delle variabili più avanti, ma in JavaScript è possibile dichiarare una variabile senza assegnarle un valore. Facendo questo, il tipo della variabile creata sarà undefined.

JavaScript ha il tipo booleano, con possibili valori true (vero) e false (falso) (entrambi i quali sono parole chiave). Qualunque valore può essere convertito in booleano seguendo le seguenti regole:

  1. false, 0, la stringa vuota (""), NaN, null, e undefined diventano tutti false
  2. tutti gli altri valori diventano true

E' possibile eseguire questa conversione esplicitamente usando la funzione Boolean():

> Boolean("")
false
> Boolean(234)
true

Tuttavia, questo raramente è necessario, JavaScript eseguirà silenziosamente la conversione quando si aspetta un booleano, così come in una istruzione  if (vedi sotto). Per questa ragione, a volte si parla semplicemente di "valori veri" e "valori falsi" valori significativi che diventano true e false, rispettivamente, quando convertiti in booleani. In alternativa, tali valori possono essere chiamati "truthy" e "falsy", rispettivamente.

Le operazioni booleane come && (and logico), || (or logico), e ! (not logico) sono supportate; vedi sotto.

Variabili

Le nuove varibili sono dichiarate in JavaScript utilizzando la parola chiave var:

var a;
var name = "simon";

Se la variabile viene dichiarata senza assegnarle un valore, il suo tipo sarà undefined

Una differenza importante rispetto ad altri linguaggi come Java è che in JavaScript, i blocchi non hanno ambito; solo le funzioni hanno ambito. Quindi se una variabile viene definita utilizzando var in una istruzione composta (ad esempio all'interno di una struttura di controllo if), essa sarà visibile da parte dell'intera funzione.

Operatori

Gli operatori numerici in JavaScript sono +, -, *, /% - che è l'operatore per il resto. I valori sono assegnanti usando =, e vi sono anche le istruzioni di assegnamento composte tipo += e -=. Questi comprimono la forma x = x operatore y.

x += 5
x = x + 5

E' possibile utilizzare ++ e -- per incrementare e decrementare rispettivamente. Questi possono essere usati come operatori prefissi o postfissi.

L'operatore + compie anche la concatenazione di stringhe:

> "hello" + " world"
hello world

Se si somma una stringa ad un numero (o ad un altro valore) tutto viene convertito dalla prima stringa. Questo esempio potrebbe aiutare a chiarire il tutto:

> "3" + 4 + 5
345
> 3 + 4 + "5"
75

Sommare una stringa vuota ad un altro tipo è un utile maniera per convertirlo.

I confronti in JavaScript possono essere eseguiti usando <, >, <= e >=. Essi funzionano sia per le stringhe che per i numeri. L'uguaglianza è un pochino meno lineare. L'operatore di doppio uguale esegue la coercizione di tipo se viene eseguita tra tipi differenti, con a volte risultati interessanti:

> "dog" == "dog"
true
> 1 == true
true

Per evitare la coercizione di tipo, si utilizza l'operatore triplo uguale:

> 1 === true
false
> true === true
true

Vi sono anche gli operatori !=!== .

JavaScript ha inoltre le operazioni bit per bit. Se si desidera utilizzarle, sono lì.

Strutture di controllo

JavaScript ha una serie di strutture di controllo simili agli altri linguaggi della famiglia del C. Le istruzioni condizionali sono supportate da if e else (se e altrimenti) che possono essere concatenati insieme se desiderato:

var name = "kittens";
if (name == "puppies") {
  name += "!";
} else if (name == "kittens") {
  name += "!!";
} else {
  name = "!" + name;
}
name == "kittens!!"

JavaScript ha il ciclo while ed il ciclo do-while. Il primo è utile per un ciclo basico; il secondo per i cicli che si vuole essere sicuri che vengano eseguiti almeno una volta:

while (true) {
  // an infinite loop!
}

var input;
do {
  input = get_input();
} while (inputIsNotValid(input))

Il ciclo for in JavaScript è lo stesso che in C e Java: esso permette di fornire le informazioni di controllo per il ciclo in una linea singola.

for (var i = 0; i < 5; i++) {
  // Will execute 5 times
}

Gli operatori &&(and logico) e ||(or logico) usano un corto-circuito logico, questo significa che quando vengono eseguiti il secondo operando è dipendente dal primo. Questo è utile per verificare oggetti nulli prima di accedere ai loro attributi:

var name = o && o.getName();

Oppure per impostare valori di default:

var name = otherName || "default";

JavaScript ha un operatore ternario per espressioni condizionali:

var allowed = (age > 18) ? "yes" : "no";

L'istruzione switch può essere utilizzata per più diramazioni sulla base di un numero o una stringa:

switch(action) {
    case 'draw':
        drawit();
        break;
    case 'eat':
        eatit();
        break;
    default:
        donothing();
}

Se non viene inserita l'istruzione break, l'esecuzione "naufragherà" nel prossimo livello. Questo è raramente il risultato voluto — in realtà vale la pena in particolare inserire un etichettatura deliberatamente con un commento, se vi vuole aiutare il debug:

switch(a) {
    case 1: // fallthrough
    case 2:
        eatit();
        break;
    default:
        donothing();
}

La clausula default è opzionale. Si possono avere espressioni sia nello switch sia che nel case se si vuole; i confronti avvengono tra i due con l'operatore ===:

switch(1 + 3) {
    case 2 + 2:
        yay();
        break;
    default:
        neverhappens();
}

Oggetti

Gli oggetti JavaScript sono semplicemente collezioni di coppie nome-valore. Come tali, essi sono simili a:

  • Dizionari in Python
  • Hashes in Perl e Ruby
  • Hash tables in C e C++
  • HashMaps in Java
  • Array associativi in PHP

Il fatto che questa struttura dati è così diffusa è la prova della sua versatilità. Dal momento che tutto (barra i tipi base) in JavaScript è un oggetto, qualunque programma JavaScript implica naturalmente un grande ricorso alla ricerca nelle tabelle hash. E' buona cosa che siano così veloci!

La parte "name" è una stringa JavaScript, mentre il valore può essere qualunque valore JavaScript — incluso più oggetti. Questo permette di costruire strutture dati di complessità arbitraria.

Ci sono due modalità di base per creare un oggetto vuoto:

var obj = new Object();

E:

var obj = {};

Entrambe sono semanticamente equivalenti; la seconda è chiamata sintassi letterale dell'oggetto, ed è più conveniente. Questa sintassi è anche la base del formato JSON e dovrebbe essere preferita ogni volta.

Una volta creato si può accedere alle proprietà di un oggetto in una o due modalità:

obj.name = "Simon";
var name = obj.name;

E...

obj["name"] = "Simon";
var name = obj["name"];

Anche queste sono semanticamente equivalenti. Il secondo metodo ha il vantaggio che il nome della proprietà viene fornito come stringa, che significa che può essere calcolato durante l'esecuzione e l'utilizzo di questo metodo evita che siano applicate ottimizzazioni del motore JavaScript e minifier. Può essere inoltre usato per impostare o ottenere proprietà con nomi che sono parole riservate:

obj.for = "Simon"; // Syntax error, because 'for' is a reserved word
obj["for"] = "Simon"; // works fine

La sintassi dell'oggetto letterale può essere usata per inizializzare un oggetto nella sua interezza:

var obj = {
    name: "Carrot",
    "for": "Max",
    details: {
        color: "orange",
        size: 12
    }
}

Attributi di accesso possono essere concatenati:

> obj.details.color
orange
> obj["details"]["size"]
12

Array (matrici)

Gli array in JavaScript sono un tipo speciale di oggetto. Essi funzionano in modo molto simile agli oggetti regolari (si può accedere alle proprietà numeriche solo usando la sintassi []) ma hanno una proprietà magica chiamata 'length'. Questa è sempre uno in più dell'indice massimo dell'array.

Il vecchio metodo per creare un array è il seguente:

> var a = new Array();
> a[0] = "dog";
> a[1] = "cat";
> a[2] = "hen";
> a.length
3

Una notazione più conveniente è l'utilizzo di una array letterale:

> var a = ["dog", "cat", "hen"];
> a.length
3

Lasciare una virgola finale al termine di un array letterale è incompatibile tra i browser, quindi non fatelo.

Nota che array.length non è necessariamente il numero di elementi nell'array. Considera il seguente esempio:

> var a = ["dog", "cat", "hen"];
> a[100] = "fox";
> a.length
101

Ricorda — la lunghezza dell'array è uno più dell'indice più alto.

Se si interroga un indice dell'array inesistente, la risposta sarà undefined:

> typeof a[90]
undefined

Se si prende in considerazione quanto sopra, è possibile scorrere un array utilizzando le istruzioni seguenti:

for (var i = 0; i < a.length; i++) {
    // Do something with a[i]
}

Questo è un po' inefficiente, poichè si ricerca la proprietà length una volta ogni ciclo. Un possibile miglioramento è questo:

for (var i = 0, len = a.length; i < len; i++) {
    // Do something with a[i]
}

Un modo ancora più simpatico è questo:

for (var i = 0, item; item = a[i++];) {
    // Do something with item
}

Qui si stanno impostando due variabili. L'assegnamento nella parte centrale del ciclo for è anche verificato per veridicità — se ha successo, il ciclo continua. Siccome i viene incrementato ogni volta, gli elementi dalla matrice saranno assegnati all'elemento in ordine sequenziale. Il ciclo termina quando viene trovato un elemento "falso" (come un undefined).

Nota che questo trucco dovrebbe essere usato solo per gli array che sappiamo non contengano valori "falsi" (array di oggetti o nodi del DOM per esempio). Se si effettua l'iterazione dei dati numerici che potrebbero includere uno 0, o dati stringa che potrebbero includere la stringa vuota, è necessario utilizza l'idioma i, len in sostituzione.

Un altro modo per iterare è di utilizzare il ciclo for...in. Nota che se vengono aggiunte nuove proprietà all' Array.prototype, saranno anch'esse iterate da questo ciclo:

for (var i in a) {
  // Do something with a[i]
}

Se si vuole accodare un elemento all'array, la maniera più sicura per farlo è questa:

a[a.length] = item;                 // same as a.push(item);

Poichè a.length è uno in più dell'indice più alto, si può essere sicuri che l'elemento sarà assegnato ad una posizione vuota alla fine dell'array.

Gli arrays nascono con alcuni metodi:

Method name Description
a.toString()  
a.toLocaleString()  
a.concat(item[, itemN]) Restituisce un nuovo array con gli elementi aggiunti ad esso.
a.join(sep)  
a.pop() Rimuove e restituisce l'ultimo elemento.
a.push(item[, itemN]) Push aggiunge uno o più elementi alla fine.
a.reverse()  
a.shift()  
a.slice(start, end) Restituisce un sub-array.
a.sort([cmpfn]) Riceve una funzione di comparazione opzionale.
a.splice(start, delcount[, itemN]) Permette di modificare un array cancellando una sezione e sostituendola con più elementi.
a.unshift([item]) Antepone elementi all'inizio dell'array

Funzioni

Insieme con gli oggetti, le funzioni sono la componente principale nella comprensione di JavaScript. La funzione più elementare non potrebbe essere molto più semplice:

function add(x, y) {
    var total = x + y;
    return total;
}

Ciò dimostra tutto quello che c'è da sapere sulle funzioni di base. Una funzione JavaScript può ricevere 0 (zero) o più parametri. Il corpo della funzione può contenere tutte le istruzioni che si desidera, e può dichiarare le proprie variabili che saranno locali alla stessa. L'istruzione return può essere usata per restituire un valore in qualsiasi momento, terminando la funzione. Se non viene utilizzata l'istruzione return (oppure viene restituito un valore vuoto o indefinito), JavaScript restituisce undefined.

I parametri denominati risultano più simili alle linee guida di ogni altra cosa. È possibile chiamare una funzione senza passare i parametri che si aspetta, nel qual caso saranno impostati su undefined.

> add()
NaN // You can't perform addition on undefined

È anche possibile passare più argomenti di quelli che la funzione si aspetta:

> add(2, 3, 4)
5 // added the first two; 4 was ignored

Questo può sembrare un po' sciocco, ma le funzioni hanno accesso a una variabile aggiuntiva all'interno del loro corpo chiamata argomenti, che è un oggetto simil array che detiene tutti i valori passati alla funzione. Riscriviamo la funzione somma per ricevere tutti i valori che vogliamo:

function add() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum;
}

> add(2, 3, 4, 5)
14

Questo, però, non è realmente più utile che scrivere 2 + 3 + 4 + 5. Creiamo una funzione per il calcolo della media:

function avg() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum / arguments.length;
}
> avg(2, 3, 4, 5)
3.5

Questa è piuttosto utile, ma introduce un nuovo problema. La funzione avg() riceve una lista di argomenti separati da una virgola — ma cosa succede se si vuole trovare la media di un array? Si potrebbe semplicemente riscrivere la funzione come segue:

function avgArray(arr) {
    var sum = 0;
    for (var i = 0, j = arr.length; i < j; i++) {
        sum += arr[i];
    }
    return sum / arr.length;
}
> avgArray([2, 3, 4, 5])
3.5

Ma sarebbe bello essere in grado di riutilizzare la funzione che abbiamo già creato. Fortunatamente, JavaScript permette di chiamare una funzione e di chiamarla con un array arbitrario di argomenti, usando il metodo apply() di qualunque oggetto di funzione.

> avg.apply(null, [2, 3, 4, 5])
3.5 is the array to use as arguments; the first will be discussed later on. This emphasizes the fact that functions are objects too.

JavaScript permette la creazione di funzioni anonime.

var avg = function() {
    var sum = 0;
    for (var i = 0, j = arguments.length; i < j; i++) {
        sum += arguments[i];
    }
    return sum / arguments.length;
}

Questa è semanticamente equivalente alla forma function avg(). Essa è estremamente potente, in quando consente di definire una funzione ovunque si possa normalmente inserire un espressione. Questo consente ogni sorta di trucco intelligente. Ecco un modo di "nascondere" alcune variabili locali - come in un ambito di blocco in C:

> var a = 1;
> var b = 2;
> (function() {
    var b = 3;
    a += b;
})();
> a
4
> b
2

JavaScript consente di chiamare le funzioni in modo ricorsivo. Ciò è particolarmente utile per affrontare le strutture ad albero, come ad esempio nel DOM del browser.

function countChars(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += countChars(child);
    }
    return count;
}

Questo mette in evidenza un potenziale problema con le funzioni anonime: come fare a richiamarle ricorsivamente se non hanno un nome? La risposta si trova con l'oggetto arguments, che oltre ad agire come una lista di argomenti, fornisce anche una propietà chiamata arguments.callee. L'uso della arguments.callee è deprecato e anche disabilitato nel modo strict (rigoroso). In sostituzione si devono utilizzare le "funzioni anonime nominate" come di seguito:

var charsInBody = (function counter(elm) {
    if (elm.nodeType == 3) { // TEXT_NODE
        return elm.nodeValue.length;
    }
    var count = 0;
    for (var i = 0, child; child = elm.childNodes[i]; i++) {
        count += counter(child);
    }
    return count;
})(document.body);

Il nome fornito a una funzione anonima come sopra è (o almeno dovrebbe essere) disponibile solo nell'ambito stesso della funzione. Questo consente sia più ottimizzazioni da svolgere da parte del motore sia un codice più leggibile.

Oggetti personalizzati

Nota: Per una discussione più dettagliata della programmazione orientata agli oggetti, vedi Introduzione a JavaScript Orientato agli Oggetti.

Nella programmazione Object Oriented classica, gli oggetti sono collezioni di dati e metodi che operano su quei dati. JavaScript è un linguaggio basato su prototipi e non contiene l'istruzione classe, così come si trova in C++ o Java. (Questo a volte è fonte di confusione per i programmatori abituati ai linguaggi con una dichiarazione di classe.) Al suo posto, JavaScript usa le funzioni come classi. Consideriamo un oggetto persona con i campi nome e cognome. Ci sono due modi di visualizzare il nominativo: come  "nome cognome" o come "cognome, nome". Usando le funzioni e gli oggetti che abbiamo visto in precedenza, ecco un modo di ottenere il risultato voluto:

function makePerson(first, last) {
    return {
        first: first,
        last: last
    }
}
function personFullName(person) {
    return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
    return person.last + ', ' + person.first
}
> s = makePerson("Simon", "Willison");
> personFullName(s)
Simon Willison
> personFullNameReversed(s)
Willison, Simon

Questo funziona, ma è piuttosto brutto. Si finisce con dozzine di funzioni nel namespace globale. Ciò di cui abbiamo veramente bisogno è un modo per associare una funzione ad un oggetto. Dal momento che le funzioni sono oggetti, questo è facile:

function makePerson(first, last) {
    return {
        first: first,
        last: last,
        fullName: function() {
            return this.first + ' ' + this.last;
        },
        fullNameReversed: function() {
            return this.last + ', ' + this.first;
        }
    }
}
> s = makePerson("Simon", "Willison")
> s.fullName()
Simon Willison
> s.fullNameReversed()
Willison, Simon

Vi è qualcosa che non abbiamo visto prima: la parola chiave 'this'. Usata dentro una funzione, 'this' si riferisce all'oggetto corrente. Che cosa significa in realtà è specificato dal modo in cui è stata chiamata tale funzione. Se è stata chiamata usando la notazione col punto o la notazione con le parentesi su un oggetto, questo oggetto diventa 'this'. Se la notazione col punto non è stata usata per la chiamata, 'this' si riferisce all'oggetto globale. Questa è una causa di errori frequente. Ad esempio:

> s = makePerson("Simon", "Willison")
> var fullName = s.fullName;
> fullName()
undefined undefined

Quando chiamiamo fullName(), 'this' è legata all'oggetto globale. Dato che non ci sono variabili globali chiamate first o last riceviamo undefined per ognuna delle due.

Possiamo prendere il vantaggio della parola chiave 'this' per migliorare la nostra funzione makePerson:

function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = function() {
        return this.first + ' ' + this.last;
    }
    this.fullNameReversed = function() {
        return this.last + ', ' + this.first;
    }
}
var s = new Person("Simon", "Willison");

Abbiamo introdotto un'altra parola chiave: 'new'. new è fortemente correlata a 'this'. Quello che fa è creare un oggetto vuoto nuovo di zecca e quindi chiamare la funzione specificata, con 'this' impostato sul nuovo oggetto. Le funzioni che sono disegnate per essere richiamate dalla ' new' sono chiamate costruttori. La pratica comune è di nominare queste funzioni con la prima lettera maiuscola in modo da ricordarsi di chiamarle con il new.

I nostri oggetti persona stanno migliorando, ma vi sono ancora alcuni lati brutti in loro. Ogni volta che si crea un oggetto persona, stiamo creando due nuovi oggetti funzione all'interno di esso - non sarebbe meglio se il codice fosse stato condiviso?

function personFullName() {
    return this.first + ' ' + this.last;
}
function personFullNameReversed() {
    return this.last + ', ' + this.first;
}
function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName;
    this.fullNameReversed = personFullNameReversed;
}

Così va meglio: stiamo creando i metodi della funzione una sola volta, e assegnando ad essi i riferimenti all'interno del costruttore. Possiamo fare di meglio? La risposta è sì:

function Person(first, last) {
    this.first = first;
    this.last = last;
}
Person.prototype.fullName = function() {
    return this.first + ' ' + this.last;
}
Person.prototype.fullNameReversed = function() {
    return this.last + ', ' + this.first;
}

Person.prototype è un oggetto condiviso da tutte le istanze di Person. Essa fa parte di una catena di ricerca (che ha un nome speciale, "catena di prototipi"): ogni volta che si tenta di accedere ad una proprietà di Person che non è impostata, JavaScript controllerà Person.prototype per vedere se quella proprietà esiste al suo interno. Come risultato, qualsiasi valore assegnato a Person.prototype diventa disponibile a tutte le istanze del costruttore per mezzo dell'oggetto this.

Si tratta di uno strumento incredibilmente potente. JavaScript consente di modificare il prototipo di qualcosa in qualsiasi momento nel programma, il che significa che è possibile aggiungere metodi extra per gli oggetti esistenti in fase di esecuzione:

> s = new Person("Simon", "Willison");
> s.firstNameCaps();
TypeError on line 1: s.firstNameCaps is not a function
> Person.prototype.firstNameCaps = function() {
    return this.first.toUpperCase()
}
> s.firstNameCaps()
SIMON

È interessante notare che è anche possibile aggiungere le cose al prototipo degli oggetti nativi JavaScript. Aggiungiamo un metodo a String che restituisca la stringa al contrario:

> var s = "Simon";
> s.reversed()
TypeError on line 1: s.reversed is not a function
> String.prototype.reversed = function() {
    var r = "";
    for (var i = this.length - 1; i >= 0; i--) {
        r += this[i];
    }
    return r;
}
> s.reversed()
nomiS

Il nostro nuovo metodo funziona anche con le stringhe letterali!

> "This can now be reversed".reversed()
desrever eb won nac sihT

Come detto prima, il prototipo fa parte di una catena. La radice di questa catena è Object.prototype, i cui metodi includono toString() — è questo metodo che viene chiamato quando si tenta di rappresentare un oggetto come una stringa. Questo è utile per verificare il nostro oggetto Person:

> var s = new Person("Simon", "Willison");
> s
[object Object]
> Person.prototype.toString = function() {
    return '<Person: ' + this.fullName() + '>';
}
> s
<Person: Simon Willison>

Ricordate come avg.apply() aveva un primo argomento nullo? Possiamo riesaminarlo adesso. Il primo argomento di apply() è l'oggetto che dovrebbe essere trattato come 'this'. Per esempio, qui una semplice implementazione di 'new':

function trivialNew(constructor) {
    var o = {}; // Create an object
    constructor.apply(o, arguments);
    return o;
}

Questa non è un'esatta replica di new in quanto non imposta la catena del prototipo (sarebbe difficile da illustrare). Non è una cosa che si usa molto spesso, ma è utile conoscerla. In questo snippet,  ...args (puntini inclusi) è chiamato il "rest arguments " – come indicato dal nome, e contiene il resto degli argomenti. Per ora, questa "feature" è sperimentale e solo disponibile in Firefox; è raccomandato attaccare gli arguments  per ora.

Chiamare

var bill = trivialNew(Person, "William", "Orange");
 

è dunque quasi equivalente a

var bill = new Person("William", "Orange");
 

apply() ha una funzione sorella dal nome call , che di nuovo ti consente di impostare 'this' ma prende una lista espansa di argomenti invece che un array.

function lastNameCaps() {
    return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();

Inner functions

In JavaScript è consentito dichiarare una funzione all'interno di un'altra funzione. Lo abbiamo già visto prima, nel caso della precedente funzione makePerson(). Un dettaglio importante di funzioni innestate in JavaScript è che esse possono accedere alle variabili della funzione di livello superiore:

function betterExampleNeeded() {
    var a = 1;
    function oneMoreThanA() {
        return a + 1;
    }
    return oneMoreThanA();
}

Ciò è di grande utilità per scrivere codice più manutenibile. Se una funzione dipende da una o due altre funzioni che non sono usate in nessuna altra parte del tuo codice, è possibile nidificare quelle funzioni di utilità dentro la funzione che sarà chiamata dall'esterno. Questo riduce il numero di funzioni che si trovano nel "global scope", che è sempre una buona cosa.

Questa è anche una grande cosa contro il richiamo di variabili globali. Quando si scrive codice complesso si è spesso tentati di usare variabili globali per condividere i valori tra più funzioni — e ciò rende il codice difficile da manutenere. Le funzioni nidificate possono condividere le variabili della funzione padre, così è possibile usare questo meccanismo per accoppiare le funzioni quando serve, senza contaminare il tuo namespace globale — rendi locali le variabili globali per piacere. Questa tecnica dovrebbe essere usata con parsimonia, ma è una capacità utile da avere.

Closures

Questo ci porta ad una delle più potenti astrazioni che JavaScript ha da offrire — ma anche quella che può generare più confusione. Cosa fa questo codice sotto?

function makeAdder(a) {
    return function(b) {
        return a + b;
    }
}
x = makeAdder(5);
y = makeAdder(20);
x(6)
?
y(7)
?

Il nome della funzione makeAdder dovrebbe essere esplicito: essa può creare delle nuove funzioni 'adder', che, se chiamate con un determinato argomento, lo addizionano all'argomento con il quale sono state create.

Quello che sta avvenendo qui è praticamente la stessa cosa vista precedentemente con le "inner functions": una funzione definita dentro un'altra funzione ha accesso alle variabili della funzione esterna. La sola differenza è che in questo caso la funzione esterna ha già restituito il suo risultato, e quindi il senso comune sembrerebbe indicare che le sue variabili locali non siano più disponibili. Ma esse esistono ancora — altrimenti le funzioni "adder" non sarebbero capaci di lavorare. Quello che c'è di più è che ci sono due "copie" differenti delle variabili locali di makeAdder — una nella quale a è 5 e una nella quale a è 20. Così il risultato di quelle chiamate di funzione è il seguente:

x(6) // returns 11
y(7) // returns 27

Ecco cosa sta effettivamente avvenendo. Quando JavaScript esegue una funzione, viene creato un oggetto con il proprio ambito di visibilità ('scope object') per trattenere le variabili locali di quella funzione. Esso è inizializzato con tutte le variabili passate in ingresso alla funzione come parametri. Ciò è simile all'oggetto globale in cui si trovano tutte le variabili globali e le funzioni, ma con una paio di differenze importanti: primo, un nuovo 'scope object' etichettato è creato ogni volta che una funzione inizia l'esecuzione, e secondo, a differenza dell'oggetto globale (che nei bowser è accessibile come 'window') non si può accedere direttamente a questi 'scope object' dal tuo codice JavaScript. Ad esempio non c'è nessun meccanismo per iterare sulle proprietà dello 'scope object' corrente.

Quindi, quando makeAdder è chiamato viene creato un oggetto scope con una proprietà: a, che è l'argomento passato alla funzione makeAdder . A questo punto makeAdder restituisce quindi una funzione appena creata. Normalmente il raccoglitore di rifiuti  di JavaScript eliminerebbe l'oggetto scope creato per makeAdder , ma la funzione restituita mantiene un riferimento a tale oggetto scope. Di conseguenza l'oggetto scope non verrà eliminato finchè non ci saranno più riferimenti all'oggetto che la funzione makeAdder restituisce.

Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript's object system.

A closure is the combination of a function and the scope object in which it was created.

Closures let you save state — as such, they can often be used in place of objects.

Memory leaks

An unfortunate side effect of closures is that they make it trivially easy to leak memory in Internet Explorer. JavaScript is a garbage collected language — objects are allocated memory upon their creation and that memory is reclaimed by the browser when no references to an object remain. Objects provided by the host environment are handled by that environment.

Browser hosts need to manage a large number of objects representing the HTML page being presented — the objects of the DOM. It is up to the browser to manage the allocation and recovery of these.

Internet Explorer uses its own garbage collection scheme for this, separate from the mechanism used by JavaScript. It is the interaction between the two that can cause memory leaks.

A memory leak in IE occurs any time a circular reference is formed between a JavaScript object and a native object. Consider the following:

function leakMemory() {
    var el = document.getElementById('el');
    var o = { 'el': el };
    el.o = o;
}

The circular reference formed above creates a memory leak; IE will not free the memory used by el and o until the browser is completely restarted.

The above case is likely to go unnoticed; memory leaks only become a real concern in long running applications or applications that leak large amounts of memory due to large data structures or leak patterns within loops.

Leaks are rarely this obvious — often the leaked data structure can have many layers of references, obscuring the circular reference.

Closures make it easy to create a memory leak without meaning to. Consider this:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}

The above code sets up the element to turn red when it is clicked. It also creates a memory leak. Why? Because the reference to el is inadvertently caught in the closure created for the anonymous inner function. This creates a circular reference between a JavaScript object (the function) and a native object (el).

needsTechnicalReview();

There are a number of workarounds for this problem. The simplest is not to use the el variable:

function addHandler(){
    document.getElementById('el').onclick = function(){
        this.style.backgroundColor = 'red';
    }
}

Surprisingly, one trick for breaking circular references introduced by a closure is to add another closure:

function addHandler() {
    var clickHandler = function() {
        this.style.backgroundColor = 'red';
    };
    (function() {
        var el = document.getElementById('el');
        el.onclick = clickHandler;
    })();
}

The inner function is executed straight away, and hides its contents from the closure created with clickHandler.

Another good trick for avoiding closures is breaking circular references during the window.onunload event. Many event libraries will do this for you. Note that doing so disables bfcache in Firefox 1.5, so you should not register an unload listener in Firefox, unless you have other reasons to do so.

Original Document Information

  • Author: Simon Willison
  • Last Updated Date: March 7, 2006
  • Copyright: © 2006 Simon Willison, contributed under the Creative Commons: Attribute-Sharealike 2.0 license.
  • More information: For more information about this tutorial (and for links to the original talk's slides), see Simon's Etech weblog post.