Variabili

Le variabili sono una struttura di dati che assegna un nome rappresentativo a un valore. Possono contenere dati di qualsiasi tipo.

Il nome di una variabile è chiamato identificatore. Un identificatore valido deve rispettare queste regole:

  • Gli identificatori possono contenere lettere Unicode, segni di dollaro ($), caratteri trattini bassi (_), cifre (0-9) e persino alcuni caratteri Unicode.
  • Gli identificatori non possono contenere spazi vuoti, perché l'analizzatore li utilizza per separare gli elementi di input. Ad esempio, se provi a chiamare una variabilemy Variable anziché myVariable, il parser vede due identificatori,my e Variable, e genera un errore di sintassi ("token imprevisto: identificatore").
  • Gli identificatori devono iniziare con una lettera, un trattino basso (_) o un segno di dollaro ($). Non possono iniziare con cifre, per evitare confusione tra numeri e identificatori:

    let 1a = true;
    
    > Uncaught SyntaxError: Invalid or unexpected token
    

    Se JavaScript consentisse i numeri all'inizio di un identificatore, verrebbero consentiti identificativi costituiti solo da numeri, causando conflitti tra i numeri utilizzati come numeri e i numeri utilizzati come identificatori:

    let 10 = 20
    
    10 + 5
    > ?
    
  • Le "parole riservate" che hanno già un significato sintattico non possono essere utilizzate come identificatori.

  • Gli identificatori non possono contenere caratteri speciali (! . , / \ + - * =).

Di seguito non sono riportate regole rigide per la creazione di identificatori, ma si tratta di best practice del settore che semplificano la gestione del codice. Se il tuo progetto specifico ha standard diversi, segui quelli per garantire la coerenza.

Seguendo l'esempio dei metodi e delle proprietà integrati di JavaScript, il Camel Case (stilizzato anche come "camelCase") è una convenzione molto comune per gli identificatori composti da più parole. Le maiuscole iniziali sono la pratica di mettere in maiuscolo la prima lettera di ogni parola tranne la prima per migliorare la leggibilità senza spazi.

let camelCasedIdentifier = true;

Alcuni progetti utilizzano altre convenzioni di denominazione, a seconda del contesto e della natura degli dati. Ad esempio, la prima lettera di un comando viene in genere scritta in maiuscolo, pertanto i nomi dei comandi composti da più parole spesso utilizzano una variante del lettering incamelcase comunemente chiamata "upper camel case" o lettering inPascal.

class MyClass {

}

Gli identificatori devono descrivere in modo conciso la natura dei dati che contengono (ad esempio, currentMonthDays è un nome migliore di theNumberOfDaysInTheCurrentMonth) e essere facilmente leggibili a colpo d'occhio (originalValue è meglio di val). Gli identificatori myVariable utilizzati in questo modulo funzionano nel contesto di esempi isolati, ma non sono molto utili nel codice di produzione perché non forniscono informazioni sui dati che contengono.

Gli identificatori non devono essere troppo specifici sui dati che contengono, perché i loro valori possono cambiare a seconda di come gli script agiscono su questi dati o in base alle decisioni prese dai futuri manutentori. Ad esempio, una variabile a cui è stato inizialmente assegnato l'identificatore miles potrebbe dover essere modificata in un valore in chilometri in un secondo momento nel progetto, richiedendo ai manutentori di modificare i riferimenti a quella variabile per evitare confusione futura. Per evitare che ciò accada, usa distance come identificatore.

JavaScript non assegna alcun privilegio o significato speciale agli identificatori che iniziano con i caratteri underscore (_), ma in genere vengono utilizzati per indicare che una variabile, un metodo o una proprietà è "privata", ovvero che è destinata esclusivamente all'uso all'interno del contesto dell'oggetto che la contiene e non deve essere acceduta o modificata al di fuori di questo contesto. Si tratta di una convenzione mutuata da altri linguaggi di programmazione e risalente a prima dell'aggiunta delle proprietà private di JavaScript.

Dichiarazione di variabili

Esistono diversi modi per informare JavaScript di un identificatore, un processo chiamato "dichiarazione" di una variabile. Una variabile viene dichiarata utilizzando le parole chiave let, const o var.

let myVariable;

Utilizza let o var per dichiarare una variabile che può essere modificata in qualsiasi momento. Queste chiavi di parola indicano all'interprete JavaScript che una stringa di caratteri è un identificatore che potrebbe contenere un valore.

Quando lavori in una base di codice moderna, utilizza let anziché var. var funziona ancora nei browser moderni, ma presenta alcuni comportamenti non intuitivi che sono stati definiti nelle prime versioni di JavaScript e che non potevano essere modificati in un secondo momento per preservare la compatibilità con le versioni precedenti. let è stato aggiunto in ES6 per risolvere alcuni problemi con il design di var.

Una variabile dichiarata viene inizializzata assegnando un valore alla variabile. Utilizza un singolo segno uguale (=) per assegnare o riassegnare un valore a una variabile. Puoi farlo nell'ambito della stessa dichiarazione che la dichiara:

let myVariable = 5;

myVariable + myVariable
> 10

Puoi anche dichiarare una variabile con let (o var) senza inizializzarla subito. In questo caso, il valore iniziale della variabile è undefined finché il codice non le assegna un valore.

let myVariable;

myVariable;
> undefined

myVariable = 5;

myVariable + myVariable
> 10

Una variabile con un valore undefined è diversa da una variabile non definita il cui identificatore non è stato ancora dichiarato. Il riferimento a una variabile non dichiarata causa un errore.

myVariable
> Uncaught ReferenceError: myVariable is not defined

let myVariable;

myVariable
> undefined

L'associazione di un identificatore a un valore è generalmente chiamata "associazione". La sintassi che segue le parole chiave let, var o const è chiamata "elenco di associazioni" e consente più dichiarazioni di variabili separate da virgole (che terminano con il punto e virgola previsto). Di conseguenza, i seguenti snippet di codice sono funzionalmente identici:

let firstVariable,
     secondVariable,
     thirdVariable;
let firstVariable;
let secondVariable;
let thirdVariable;

Per riassegnare il valore di una variabile non viene utilizzato let (o var), perché JavaScript sa già che la variabile esiste:

let myVariable = true;

myVariable
> true

myVariable = false;

myVariable
> false

Puoi riassegnare nuovi valori alle variabili in base ai valori esistenti:

let myVariable = 10;

myVariable
> 10

myVariable = myVariable * myVariable;

myVariable
> 100

Se provi a ridefinire una variabile utilizzando let in un ambiente di produzione, verrà visualizzato un errore di sintassi:

let myVariable = true;
let myVariable = false;
> Uncaught SyntaxError: redeclaration of let myVariable

Gli strumenti per sviluppatori dei browser sono più permissivi in merito alla ridefinizione di let (e class), pertanto potresti non vedere lo stesso errore nella console per sviluppatori.

Per preservare la compatibilità con i browser precedenti, var consente la rideclarazione non necessaria senza errori in qualsiasi contesto:

var myVariable = true;
var myVariable = false;

myVariable\
> false

const

Utilizza la parola chiave const per dichiarare una costante, un tipo di variabile che deve essere inizializzata immediatamente e che non può essere modificata. Gli identificatori per le costanti seguono tutte le stesse regole delle variabili dichiarate utilizzando let (e var):

const myConstant = true;

myConstant
> true

Non puoi dichiarare una costante senza assegnarle immediatamente un valore, perché le costanti non possono essere riassegnate dopo la loro creazione, quindi qualsiasi costante non inizializzata rimarrebbe undefined per sempre. Se provi a dichiarare una costante senza inizializzala, viene visualizzato un errore di sintassi:

const myConstant;
Uncaught SyntaxError: missing = in const declaration

Il tentativo di modificare il valore di una variabile dichiarata con const nel modo in cui potresti modificare il valore di una variabile dichiarata con let (o var) causa un errore di tipo:

const myConstant = true;

myConstant = false;
> Uncaught TypeError: invalid assignment to const 'myConstant'

Tuttavia, quando una costante è associata a un oggetto, le proprietà di quell'oggetto possono essere modificate.

const constantObject = { "firstvalue" : true };

constantObject
> Object { firstvalue: true }

constantObject.secondvalue = false;

constantObject
> Object { firstvalue: true, secondvalue: false }

Una costante che contiene un oggetto è un immutabile riferimento a un valore di dati mutabile. Sebbene la costante stessa non possa essere modificata, le proprietà dell'oggetto a cui si fa riferimento possono essere alterate, aggiunte o rimosse:

const constantObject = { "firstvalue" : true };

constantObject = false
> Uncaught TypeError: invalid assignment to const 'constantObject'

Quando non prevedi che una variabile venga riassegnata, è buona prassi impostarla come costante. L'utilizzo di const indica al team di sviluppo o ai futuri responsabili di un progetto di non modificare il valore, per evitare di violare le ipotesi fatte dal codice sul suo utilizzo, ad esempio che una variabile verrà valutata in base a un tipo di dati previsto.

Ambito della variabile

L'ambito di una variabile è la parte di uno script in cui è disponibile. Al di fuori dell'ambito di una variabile, non verrà definita, non come identificatore contenente un valore undefined, ma come se non fosse stata dichiarata.

A seconda della parola chiave utilizzata per dichiarare una variabile e del contesto in cui la definisci, puoi definire l'ambito delle variabili per gli statement di blocco (ambito blocco), per le singole funzioni (ambito funzione) o per l'intera applicazione JavaScript (ambito globale).

Ambito del blocco

Qualsiasi variabile dichiarata utilizzando let o const ha come ambito la istruzione di blocco contenente più vicina, il che significa che è possibile accedere alla variabile solo all'interno di quel blocco. Il tentativo di accedere a una variabile con ambito a blocchi al di fuori del blocco contenente causa lo stesso errore del tentativo di accedere a una variabile inesistente:

{
    let scopedVariable = true;
    console.log( scopedVariable );
}
> true

scopedVariable
> ReferenceError: scopedVariable is not defined

Per quanto riguarda JavaScript, una variabile con ambito a livello di blocco non esiste al di fuori del blocco che la contiene. Ad esempio, puoi dichiarare una costante all'interno di un blocco e poi dichiararne un'altra al di fuori del blocco che utilizza lo stesso identificatore:

{
  const myConstant = false;
}
const myConstant = true;

scopedConstant;
> true

Sebbene una variabile dichiarata non possa estendersi al blocco principale, è disponibile per tutti i blocchi discendenti:

{
    let scopedVariable = true;
    {
    console.log( scopedVariable );
    }
}
> true

Il valore di una variabile dichiarata può essere modificato da un blocco discendente:

{
    let scopedVariable = false;
    {
    scopedVariable = true;
    }
    console.log( scopedVariable );
}
> true

Una nuova variabile può essere inizializzata con let o const all'interno di un blocco di descendenti senza errori, anche se utilizza lo stesso identificatore di una variabile in un blocco principale:

{
    let scopedVariable = false;
    {
    let scopedVariable = true;
    }
    console.log( scopedVariable );
}
> false

Ambito funzione

Le variabili dichiarate utilizzando var hanno come ambito la funzione contenitore più vicina (o il blocco di inizializzazione statica all'interno di una classe).

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

Questo accade anche dopo aver chiamato una funzione. Anche se la variabile viene inizializzata durante l'esecuzione della funzione, non è ancora disponibile al di fuori dell'ambito della funzione:

function myFunction() {
    var scopedVariable = true;

    return scopedVariable;
}

scopedVariable;
> ReferenceError: scopedVariable is not defined

myFunction();
> true

scopedVariable;
> ReferenceError: scopedVariable is not defined

Ambito globale

Una variabile globale è disponibile in un'intera applicazione JavaScript, all'interno di tutti i blocchi e le funzioni, per qualsiasi script nella pagina.

Sebbene possa sembrare un valore predefinito auspicabile, le variabili a cui qualsiasi parte di un'applicazione può accedere e modificare possono aggiungere un overhead non necessario o addirittura causare collisioni con variabili presenti in altre parti dell'applicazione con lo stesso identificatore. Questo vale per qualsiasi codice JavaScript coinvolto nel rendering di una pagina, inclusi elementi come librerie di terze parti e analisi degli utenti. Pertanto, è buona prassi evitare di inquinare l'ambito globale, se possibile.

Qualsiasi variabile dichiarata utilizzando var al di fuori di una funzione principale o utilizzando let o const al di fuori di un blocco principale è globale:

var functionGlobal = true; // Global
let blockGlobal = true; // Global

{
    console.log( blockGlobal );
    console.log( functionGlobal );
}
> true
> true

(function() {
    console.log( blockGlobal );
    console.log( functionGlobal );
}());
> true
> true

L'assegnazione di un valore a una variabile senza dichiararla esplicitamente (ovvero senza mai utilizzare var, let o const per crearla) esegue l'elevazione della variabile allo scopo globale, anche se inizializzata all'interno di una funzione o di un blocco. Una variabile creata utilizzando questo pattern a volte è chiamata "globale implicita".

function myFunction() {
    globalVariable = "global";

    return globalVariable
}

myFunction()\
> "global"

globalVariable\
> "global"

Sollevamento delle variabili

Le dichiarazioni di variabili e funzioni vengono elevate nella parte superiore del loro ambito, il che significa che l'interprete JavaScript elabora qualsiasi variabile dichiarata in qualsiasi punto di uno script e la sposta efficacemente nella prima riga del suo ambito di contenimento prima di eseguire lo script. Ciò significa che a una variabile dichiarata utilizzando var può essere fatto riferimento prima che la variabile venga dichiarata senza riscontrare un errore:

hoistedVariable
> undefined

var hoistedVariable;

Poiché viene ospitata solo la dichiarazione della variabile, non l'inizializzazione, le variabili che non sono state dichiarate esplicitamente con var, let o const non vengono sollevate:

unhoistedVariable;
> Uncaught ReferenceError: unhoistedVariable is not defined

unhoistedVariable = true;

Come accennato in precedenza, a una variabile dichiarata, ma non inizializzata, viene assegnato un valore undefined. Questo comportamento si applica anche alle dichiarazioni di variabili elevate, ma solo a quelle dichiarate utilizzando var.

hoistedVariable
> undefined

var hoistedVariable = 2 + 2;

hoistedVariable\
> 4

Questo comportamento non intuitivo è in gran parte un retaggio delle decisioni di progettazione prese nelle prime versioni di JavaScript e non può essere modificato senza il rischio di interrompere i siti esistenti.

let e const risolvono questo comportamento generando un errore quando si accede a una variabile prima che venga creata:

{
    hoistedVariable;

    let hoistedVariable;
}
> Uncaught ReferenceError: can't access lexical declaration 'hoistedVariable' before initialization

Questo errore è diverso da "hoistedVariable non è definito", che potresti aspettarti quando provi ad accedere a una variabile non dichiarata. Poiché JavaScript ha sollevato la variabile, sa che verrà creata nell'ambito specificato. Tuttavia, anziché rendere disponibile la variabile prima della sua dichiarazione con un valore di undefined, l'interprete genera un errore. Le variabili dichiarate con let o const (o class) si dice che esistano in una "zona morta temporale" ("TDZ") dall'inizio del blocco che le racchiude fino al punto del codice in cui la variabile è dichiarata.

La zona morta temporale rende il comportamento di let più intuitivo rispetto a var per gli autori. È inoltre fondamentale per la progettazione di const. Poiché le costanti non possono essere modificate, una costante spostata nella parte superiore del suo ambito e a cui è stato assegnato un valore implicito di undefined non può essere inizializzata con un valore significativo.

Verificare di aver compreso

Con quali tipi di caratteri puoi iniziare un identificatore?

Una lettera
Un trattino basso
Una cifra

Qual è il metodo preferito per dichiarare una variabile il cui valore può essere modificato in qualsiasi momento?

let
const
var