var
La parola chiave var serve per dichiarare una variabile globally-scoped (visibile in ogni punto del programma) o function-scoped (visibile solo dentro la funzione dentro cui è stata dichiarata).
var x; //dichiarazione senza inizializzazione, x vale undefined
var x = 1; // dichiarazione e inizializzazione insieme
var first = 0, second = "ciao"; //dichiarazione di due variabili in una sola volta
var a = 3;
function func1() {
console.log(a); //3
}
func1();
var b = 5;
function func2() {
b = 7;
}
func2();
console.log(b); //7
var c = 10;
function func3() {
// variable shadowing
var c = 20; //la variabile dichiarata nella funzione rimane all'interno della funzione
}
func3();
console.log(c); //10 qui la variabile c è quella esterna, non quella dichiarata nella funzione
var d = 12;
if (true) {
var d = 24; //la variabile dichiarata non in una funzione sovrascrive la precedente
}
console.log(d); //24 qui la variabile è quella ridichiarata nel blocco if
//le variabili globali sono in realtà proprietà dell'oggetto window
console.log(window.a); //3
console.log(window.b); //7
console.log(window.c); //10
console.log(window.d); //24
console.log(window.first); //0
console.log(window.second); //"ciao"
console.log(window.func1); //"ƒ func1() { console.log(a); }"
console.log(window.func2); //"ƒ func2() { b = 7; }"
console.log(window.func3); //"ƒ func3() { var c = 20; }"
let
La parola chiave let serve per dichiarare una variabile block-scoped (visibile solo dentro il blocco di parentesi graffe in cui è stata dichiarata).
let x; //dichiarazione senza inizializzazione, x vale undefined
let x = 1; // dichiarazione e inizializzazione insieme
let first = 0, second = "ciao"; //dichiarazione di due variabili in una sola volta
var pippo;
let pippo; //Uncaught SyntaxError: Identifier 'pippo' has already been declared
let pizza;
var pizza; //Uncaught SyntaxError: Identifier 'pizza' has already been declared
let casa;
let casa; //Uncaught SyntaxError: Identifier 'pizza' has already been declared
let a = 3;
function func1() {
console.log(a); //3
}
func1();
let b = 5;
function func2() {
b = 7;
}
func2();
console.log(b); //7
let c = 10;
function func3() {
let c = 20; //
}
func3();
console.log(c); //10
let d = 12;
if (true) {
let d = 24; //questa variabile non è visibile al di fuori del blocco in cui è stata dichiarata
}
console.log(d); //12
const
La parola chiave const serve per dichiarare una variabile block-scoped che non può essere riassegnata nè ridichiarata.
const x; //Uncaught SyntaxError: Missing initializer in const declaration
const x = 1; // dichiarazione e inizializzazione insieme
const first = 0, second = "ciao"; //dichiarazione di due variabili in una sola volta
var pippo = 3;
const pippo = 3; //Uncaught SyntaxError: Identifier 'pippo' has already been declared
let pizza = 3;
const pizza = 3; //Uncaught SyntaxError: Identifier 'pizza' has already been declared
const casa = 3;
const casa = 3; //Uncaught SyntaxError: Identifier 'casa' has already been declared
const a = 3;
function func1() {
console.log(a); //3
}
func1();
const b = 5;
function func2() {
b = 7; // Uncaught TypeError: Assignment to constant variable.
}
func2();
console.log(b); //5
const c = 10;
function func3() {
const c = 20; //
}
func3();
console.log(c); //10
const d = 12;
if (true) {
const d = 24; //questa variabile non è visibile al di fuori del blocco in cui è stata dichiarata
}
console.log(d); //12
//una const non è una veria e propria costante in quanto il suo valore può essere modificato
const persona = {
nome: "Mario",
cognome: "Rossi",
anni: 20
}
persona.anni = 30;
console.log(persona); //{nome: "Mario", cognome: "Rossi", anni: 30}
Se non si usa nè var nè let nè const e non si sta usando lo strict-mode la variabile diventa una proprietà dell'oggetto window:
test = "ciao";
console.log(window.test); // "ciao", in strict mode ReferenceError
var one = 1;
let two = 2;
console.log(window.one); // 1
console.log(window.two); // undefined
Shadowing
Lo shadowing si verifica quando si dichiara una nuova variabile in un ambito interno che ha lo stesso nome di una variabile già esistente in un ambito esterno. Quando questo accade, la variabile più interna nasconde la variabile esterna.
let nome = "Mario"; //ambito esterno, globale
var animale = "Cane"; //ambito esterno, globale
function mostraNome() {
let nome = "Giovanna";
var animale = "Gatto";
console.log(nome); // mostra "Giovanna" a causa dello shadowing (con let)
console.log(animale); // mostra "Gatto" a causa dello shadowing che con var funziona nell'ambito di funzione
}
mostraNome();
console.log(nome); // mostra "Mario" perchè qui siamo fuori dall'ambito della funzione mostraNome, la variabile let locale è distrutta al di fuori della funzione
console.log(animale); // mostra "Cane" perchè qui siamo fuori dall'ambito della funzione mostraNome, la variabile var locale è distrutta
let counter = 10;
var year = 1982;
var altezza = 157;
if (true) {
counter = 20; // qui non stiamo dichiarando un'altra variabile ma stiamo accedendo a quella esterna
year = 2025; // qui non stiamo dichiarando un'altra variabile ma stiamo accedendo a quella esterna
var altezza = 190; //var ignora lo scope di blocco e di fatto sovrascrive la variabile esterna 'altezza'. Non avviene shadowing. A causa dell'hoisting la dichiarazione della var viene spostata all'inizio dell'ambito globale (o della funzione se fossimo dentro una funzione invece che in un blocco if
console.log(counter); // mostra 20
console.log(year); // mostra 2025
console.log(altezza); // mostra 190
}
console.log(counter); // mostra 20 perchè abbiamo modificato la variabile esterna
console.log(year); // mostra 2025 perchè abbiamo modificato la variabile esterna
console.log(altezza); //mostra 190 perchè la dichiarazione interna con var ha sovrascritto quella esterna, in quanto var non ha scope di blocco.
Hoisting
E' importante dichiarare in un modo o nell'altro le var prima di utilizzarle. L'utilizzo di una var non dichiarata non provoca errori perchè le var sono memorizzate prima che il codice sia processato ma con valore undefined (hoisting). Le let e le const invece non possono essere utilizzate prima di essere dichiarate. Le funzioni invece possono essere utilizzate prima della loro dichiarazione a meno che queste non siano assegnate ad una var, in quel caso sempre a causa dell'hoisting la variabile vale undefined.
console.log(a); //Uncaught ReferenceError: a is not defined
console.log(b); //undefined
var b = 3;
console.log(c); //Uncaught ReferenceError: c is not defined
let c = 5;
console.log(d); //Uncaught ReferenceError: Cannot access 'd' before initialization
const d = 10;
func1(); //è possibile utilizzare una funzione prima di averla dichiarata
function func1() { //function declaration
console.log("func1"); //"func1"
}
func2(); //Uncaught TypeError: func2 is not a function in questo momento la variabile func2 vale undefined
var func2 = function() { //function expression
console.log("func2");
}
L'hoisting avviene perchè l'esecuzione di un programma JavaScript avviene in due fasi, prima il parsing e poi l'esecuzione.