Destrutturazione di variabili

Cos’è la destrutturazione?

In Javascript, la destrutturazione di un array o di un oggetto è una tecnica introdotta con lo standard ES2015, che permette di creare delle variabili in modo veloce e facilmente comprensibile dalle proprietà di un oggetto o dai valori di un array. Può anche essere utilizzata dopo la dichiarazione delle variabili per assegnargli dei valori.

Destrutturazione di un array

La destrutturazione degli array torna molto comoda quando riceviamo dei dati dove gli indici dell’array hanno un significato particolare.

Prendiamo, per esempio, il valore di ritorno della funzione Object.entries(...). Questa funzione ritorna una lista dove ogni elemento è una coppia chiave-valore degli attributi dell’oggetto. La coppia chiave-valore è un array di due elementi, e quindi potrebbe essere complicato, se il codice diventa lungo, capire a colpo d’occhio a cosa ci si riferisce.

let utente = {
  nome: "Mario",
  cognome: "Rossi",
  lavoro: "Web developer",
};

for (entry of Object.entries(utente)) {
  console.log("Nome attributo: " + entry[0]);
  console.log("Valore attributo: " + entry[1]);
  // Non è immediato capire cos'è entry[0] o entry[1]
}

In questo caso ci può tornare utile la destrutturazione. Ecco come farla con gli array:

let [primo, secondo, terzo] = [0, 1, 2];

console.log(primo); // 0
console.log(secondo); // 1
console.log(terzo); // 2

Mettendo i nomi delle variabili che vogliamo creare all’interno delle parentesi quadre, indichiamo che vogliamo fare la destrutturazione di un array. Le variabili verranno popolate coi valori corrispondenti alla loro posizione nella lista.

Ora ricostruiamo il ciclo dell’esempio precedente utilizzando la destrutturazione:

for ([chiave, valore] of Object.entries(utente)) {
  console.log("Nome attributo: " + chiave);
  console.log("Valore attributo: " + valore);
}

Molto più chiaro adesso!

Funzionalità più avanzate

Quello che abbiamo visto prima è già sufficiente per godere della destrutturazione degli array, ma vediamo adesso altre regole di sintassi che possono tornarci molto utili: ignorare dei valori, assegnare il resto di un array ad una variabile e impostare dei valori di default.

Per ignorare dei valori, è sufficiente inserire la virgola senza inserire un nome per la variabile. Ecco un esempio per chiarire meglio il concetto:

let [primo, , ultimo] = [0, 1, 2];

console.log(primo); // 0
console.log(ultimo); // 2

Possiamo inserire quanti campi vuoti desideriamo per ignorare anche più di un valore.

let [primo, , , quarto, , sesto] = [0, 1, 2, 3, 4, 5];

Se invece vogliamo assegnare i restanti elementi di un array ad una variabile, possiamo utilizzare l’operatore rest (i tre puntini di sospensione):

let [primo, secondo, ...restanti] = [0, 1, 2, 3, 4];

console.log(primo); // 0
console.log(secondo); // 1
console.log(restanti); // [2, 3, 4] (array con gli elementi restanti)

Infine, per assegnare un valore di default è sufficiente inserire =valore dopo il nome della variabile. Vediamo un esempio:

let [x = 10, y = 10, z = 10] = [0, 1];

console.log(x); // 0
console.log(y); // 1
console.log(z); // 10 (valore di default)

Destrutturazione di un oggetto

La destrutturazione di un oggetto funziona in modo molto simile a quella dell’array, con alcune particolarità legate al modo in cui le variabili vengono assegnate. La destrutturazione di un oggetto può tornare molto utile, per esempio, quando vogliamo utilizzare i parametri passati a una funzione per inizializzare dei dati. Dopo vedremo come farlo in modo più dettagliato.

Per indicare che vogliamo destrutturare un oggetto, dobbiamo inserire le parentesi graffe intorno alle variabili quando vogliamo assegnargli un valore:

let utente = {
  nome: "Mario",
  cognome: "Rossi",
};

let { nome, cognome, lavoro } = utente;

console.log(nome); // Mario
console.log(cognome); // Rossi
console.log(lavoro); // undefined

In questo caso, l’interprete cerca nell’oggetto degli attributi che hanno lo stesso nome delle variabili che stiamo creando. Se non ne trova, quella variabile risulterà undefined, come la variabile ‘lavoro’ nell’esempio sopra.

Se vogliamo effettuare la destrutturazione di un oggetto dentro a variabili che abbiamo già dichiarato, allora è importante inserire questa dichiarazione fra parentesi tonde:

let nome, cognome, lavoro;

({ nome, cognome, lavoro } = utente);

Funzionalità più avanzate

Se vogliamo assegnare un valore di default alle variabili, possiamo fare proprio come abbiamo fatto prima con gli array, cioè inserendo un =valore dopo il nome della variabile. Riprendendo l’esempio precedente:

let { nome, cognome, lavoro = "Web developer" } = utente;

console.log(nome); // Mario
console.log(cognome); // Rossi
console.log(lavoro); // Web developer

Il valore di default verrà sostituito solo quando viene trovato il valore undefined. Quindi se quell’attributo contiene una stringa vuota o un valore null, la stringa di default non verrà utilizzata.

Nel caso volessimo cambiare il nome delle variabili in modo da non essere legati a ciò che troviamo nell’oggetto, possiamo indicarlo con questa sintassi:

let user = {
  name: "Mario",
  surname: "Rossi",
};

// { nome-attributo : nuovo-nome-variabile }

let { name: nome, surname: cognome } = user;

console.log(nome); // Mario
console.log(cognome); // Rossi

Le varie possibilità che stiamo esplorando in questa sezione possono anche essere utilizzate contemporaneamente, dando quindi sia un valore di default che un nome diverso. Per esempio:

let { name: nome = "Nome utente", surname: cognome = "Cognome utente" } = user;

Destrutturazione e parametri di funzioni

Prima di questa tecnica, il metodo che veniva utilizzato per inizializzare dei valori tramite i parametri delle funzioni era abbastanza complicato e presentava delle falle. Prendiamo questa funzione come esempio:

function Utente(opzioni) {
  let nome = opzioni.nome || "Mario";
  let cognome = opzioni.cognome || "Rossi";
  let lavoro = opzioni.lavoro || "Web developer";

  // ...
}

Come si può notare, la leggibilità non è il massimo. Inoltre, se volessimo assegnare null al lavoro di questo utente, non ci sarebbe possibile, perché con questa tecnica i valori null, le stringhe vuote, gli array vuoti (e altro) vengono considerati ‘falsi’ e quindi vengono sostituiti dalla stringa di default.

Ora, grazie alla destrutturazione, possiamo riscrivere questo codice in modo più compatto, leggibile e sicuro:

function Utente({
  nome = "Mario",
  cognome = "Rossi",
  lavoro = "Web developer",
}) {
  // ...
}

Destrutturazione di oggetti annidati

Se vogliamo raggiungere dei valori dentro a degli oggetti annidati, allora la questione diventa un po’ più complicata. Qui inserire un valore di default diventa importante per non generare errori. Vediamo un esempio:

let utente = {
  nome: "Mario Rossi",
  lavoro: {
    tipologia: "Web Developer",
    orario: "Part-time",
  },
};

// Destrutturazione:
let {
  nome,
  // nome-attributo: { variabili-da-inizializzare }
  lavoro: { tipologia: tipoLavoro, orario: orarioLavoro },
} = utente; // ricordiamoci che stiamo destrutturando!

console.log(nome); // Mario Rossi
console.log(tipoLavoro); // Web Developer
console.log(orarioLavoro); // Part-time

Qui abbiamo in pratica fatto una destrutturazione dentro l’altra. Prima abbiamo destrutturato l’utente, poi abbiamo destrutturato il lavoro, assegnando gli attributi alle variabili che volevamo. Cosa succederebbe però se l’attributo lavoro non esistesse? Verrebbe generato un errore.

Per questo motivo è importante assegnare un valore di default in questo modo:

let {
  nome,
  lavoro: { tipologia: tipoLavoro, orario: orarioLavoro } = {}, // Assegnamo il valore di default. In questo caso, le variabili "tipologia" e "orario" saranno nulle.
} = utente;

Questo lavoro va fatto per ogni oggetto annidato dal quale si vuole estrarre dei dati, quindi si può immaginare come il codice possa iniziare a diventare complicato. Per questo motivo la destrutturazione dà il meglio di sé quando si ha a che fare con oggetti “piatti”, cioè senza altri oggetti annidati.

Spero che questo articolo possa esservi stato utile per esplorare questa nuova sintassi di Javascript, che sicuramente vi tornerà molto utile. Se volete avere ulteriori informazioni su questo argomento potete visitare la pagina MDN al riguardo, che spiega più nel dettaglio cose come la destrutturazione di oggetti annidati (array compresi), l’utilizzo di nomi di attributi calcolati a runtime e altro ancora.

Buon lavoro!