Le informazioni contenute in questo articolo sono utili per la comprensione dei vecchi script.
Non il modo corretto di scrive il codice oggi.
Nei primi capitoli in cui abbiamo parlato di variabili, abbiamo menzionato tre diversi tipi di dichiarazione:
letconstvar
La dichiarazione var molto simile a let.La maggior parte delle volte possiamo sostituire let con var o vice-versa, e lo script continuerebbe a funzionare senza problemi:
var message = "Hi";
alert(message); // Hi
But internally var is a very different beast, that originates from very old times. Its generally not used in modern scripts, but still lurks in the old ones.
If you dont plan on meeting such scripts you may even skip this chapter or postpone it.
E per importate capire le differenze durante la migrazione dei vecchi script da var a let, per evitare errori.
var non ha uno scope di blocco
Le variabili dichiarate tramite var possono essere: locali alla funzione oppure globali.
Ad esempio:
if (true) {
var test = true; // utilizziamo "var" piuttosto di "let"
}
alert(test); // vero, la variabile vive dopo if
Se avessimo utilizzato let test invece di var test, allora la variabile sarebbe stata visibile solo allinterno dell if.
if (true) {
let test = true; // use "let"
}
alert(test); // ReferenceError: test is not defined
La stessa cosa accade con i cicli, var non pu essere locale ad un blocco/ciclo:
for (var i = 0; i < 10; i++) {
var one = 1;
// ...
}
alert(i); // 10, "i" visibile anche dopo il ciclo, una variabile globale
alert(one); // 1, "one" visibile anche dopo il ciclo, una variabile globale
Se un blocco di codice si trova allinterno di una funzione, allora var diventa una variabile a livello di funzione:
function sayHi() {
if (true) {
var phrase = "Hello";
}
alert(phrase); // funziona
}
sayHi();
alert(phrase); // Errore: phrase non definito
Come possiamo vedere, var passa attraverso if, for o altri blocchi di codice. Questo accade perch molto tempo fa i blocchi JavaScript non possedevano un Lexical Environments. E var ne un ricordo.
var tollera dichiarazioni multiple
Se proviamo a ri-dichiarare la stessa variabile con let nello stesso scope, avremmo un errore:
let user;
let user; // SyntaxError: 'user' has already been declared
Con var, possiamo ri-dichiarare una variabile quante volte vogliamo. Se proviamo ad utilizzare var con una variabile gi dichiarata, esso verr semplicemente ignorato e la variabile verr normalmente riassegnata:
var user = "Pete";
var user = "John"; // qui "var" non fa nulla (gi dichiarata)
// ...non emetter nessun errore
alert(user); // John
Le variabili var possono essere dichiarate dopo il loro utilizzo
Le dichiarazioni con var vengono processata quando la funzione inizia (o lo script, nel caso delle variabili globali).
In altre parole, le variabili var sono definite dallinizio della funzione, non ha importanza dove vengano definite (ovviamente non vale nel caso di funzioni annidate).
Guardate questo esempio:
function sayHi() {
phrase = "Hello";
alert(phrase);
var phrase;
}
sayHi();
E tecnicamente la stessa cosa di (spostando var phrase):
function sayHi() {
var phrase;
phrase = "Hello";
alert(phrase);
}
sayHi();
O anche di questa (ricordate, i blocchi di codice vengono attraversati dallo scope della variabile):
function sayHi() {
phrase = "Hello"; // (*)
if (false) {
var phrase;
}
alert(phrase);
}
sayHi();
Questo comportamento viene chiamato sollevamento, perch tutte var vengono sollevate fino allinizio della funzione.
Quindi nellesempio sopra, if (false) il ramo non eseguir mai, ma non ha importanza. La var allinterno viene processata allinizio della funzione, quindi quando ci troviamo in (*) la variabile esiste.
Le dichiarazioni vengono sollevate, le assegnazioni no.
Lo dimostriamo con un esempio, come quello seguente:
function sayHi() {
alert(phrase);
var phrase = "Hello";
}
sayHi();
La riga var phrase = "Hello" pu essere suddivisa in due:
- Dichiarazione della variabile
var - Assegnazione della variabile con
=.
La dichiarazione viene processata allinizio della funzione (sollevata), lassegnazione invece ha luogo sempre nel posto in cui appare. Quindi il codice funziona in questo modo:
function sayHi() {
var phrase; // la dichiarazione viene processata...
alert(phrase); // undefined
phrase = "Hello"; // ...assegnazione - quando viene raggiunta dal flusso d'esecuzione.
}
sayHi();
Il fatto che la dichiarazione di var venga processata allinizio della funzione, ci consente di farne riferimento in qualsiasi punto. Ma la variabile rimane undefined fino allassegnazione.
In entrambi gli esempi sopra alert esegue senza errori, poich la variabile phrase esiste. Il suo valore per non gli ancora stato assegnato, quindi viene mostrato undefined.
IIFE
In passato, poich esisteva solo var, che non consentiva di definire variabili con visibilit a livello di blocco, i programmatori hanno inventato un modo per emulare questa situazione. Quello che facevano fu chiamato immediately-invoked function expressions (espressioni di funzioni invocate immediatamente,abbreviato come IIFE).
E qualcosa che dovremmo evitare oggi, ma possibile trovare questo trucco nei vecchi script.
Una IIFE viene scritta in questo modo:
(function() {
var message = "Hello";
alert(message); // Hello
})();
Qui, unespressione di funzione viene creata ed immediatamente chiamata. Quindi il codice esegue nel modo giusto, e possiede le sue variabili private.
Lespressione di funzione avvolta dalle parentesi (function {...}), poich quando JavaScript incontra "function" nel flusso principale del codice, lo interpreta come linizio di una dichiarazione di funzione. Ma una dichiarazione di funzione deve avere un nome, quindi questo tipo di codice daebbe un errore:
// Proviamo a dichiarare ed invocare immediatamente una funzione
function() { // <-- Errore di sintassi: La dichiarazione di funzione richiede un nome
var message = "Hello";
alert(message); // Hello
}();
Anche se dovessimo pensare di aggiungere un nome, questo codice non funzionerebbe, poich JavaScript non consente di invocare immediatamente le funzioni dichiarate:
// errore di sintassi a causa delle parentesi ()
function go() {
}(); // <-- non possibile invocare una dichiarazione di funzione immediatamente
Quindi, le parentesi intorno alla funzione sono un trucco per mostrare a JavaScript che la funzione viene creata in un altro contesto, e quindi unespressione di funzione: la quale non richiede nome e pu essere invocata immediatamente.
Esistono altri modi oltre alle parentesi per dire a JavaScript che intendiamo definire unespressione di funzione:
// Altri modi per creare una IIFE
(function() {
alert("Parentheses around the function");
})();
(function() {
alert("Parentheses around the whole thing");
}());
!function() {
alert("Bitwise NOT operator starts the expression");
}();
+function() {
alert("Unary plus starts the expression");
}();
In tutti gli esempi illustrati stiamo dichiarando unespressione di funzione invocandola immediatamente. Lasciatemelo ripetere: al giorno doggi non c alcun motivo di scrivere codice del genere.
Riepilogo
Ci sono due principali differenze tra var e let/const:
varnon hanno uno scope locale al blocco, sono infatti visibili a livello di funzione.- La dichiarazione di
varviene processata allinizio della funzione.
C un ulteriore differenza di minore importanza legata alloggetto globale, che andremo ad analizzare nel prossimo capitolo.
Linsieme di queste differenze fa si che var venga considerato uno svantaggio. Come prima cosa, non possiamo creare delle variabili locali al blocco. Il sollevamento genera solamente confusione. Quindi, negli script pi recenti var viene utilizzato solamente in casi eccezionali.
Commenti
<code>, per molte righe includile nel tag<pre>, per pi di 10 righe utilizza una sandbox (plnkr, jsbin, codepen)