Introduzione
In questo articolo vi mostro alcune sintassi (più o meno recenti) che potreste incontrare nel codice e che raramente vengono spiegate.
Solo perché queste funzionalità sono disponibili, non significa che vadano usate ogni volta che ce n’è la possibilità! Valutate sempre attentamente se è possibile rendere il vostro codice più leggibile 🙂️
Block statements
Probabilmente sapete che quando si usano costrutti come gli if
o i for
, viene creato un nuovo “blocco” di codice:
if (condizione) {
// Un blocco di codice. Niente di strano qui...
// 'let' creerà una variabile disponibile solo dentro l'if
let variabile = "";
}
Sapevate però che è possibile anche dichiarare un blocco senza usare un ciclo o una condizione? E’ sufficiente usare le parentesi graffe, in questo modo:
let a = 1;
{
// Nuovo blocco di codice
let b = 2;
console.log(a); // 1
console.log(b); // 2
}
console.log(b); // ReferenceError: b is not defined
In questo modo possiamo dichiarare delle variabili che potranno essere utilizzate solo in specifiche porzioni di codice: un’ottima alternative alle IIFE quando vogliamo gestire meglio lo scope!
L’operatore “null Coalescing”
Questo operatore, insieme a quello per l’optional binding, sono decisamente recenti. Introdotti per la prima volta quest’anno, risolvono un bel po’ di problemi che finora hanno creato molti fastidi agli sviluppatori.
Probabilmente in passato avete utilizzato un codice simile a questo:
let variabile = opzioni.valore || "default";
Questo codice utilizza l’operatore logico “OR” per controllare se la proprietà valore
esiste nelle opzioni, altrimenti
assegna alla variabile un valore di default.
Questo però diventa un problema se per noi valori come 0
, ""
o []
sono accettabili. L’operatore “OR” tradurrà queste
variabili con false
, e quindi assegnerà il valore di default.
L’operatore null coalescing
, invece, permette di controllare se una variabile è null
o undefined
.
Possiamo usarlo in questo modo:
let opzioni = {
valore: 0,
};
// Proviamo ad assegnare il valore con l'operatore OR
let operatoreOr = opzioni.valore || "default"; // --> "default"
// Usiamo ora l'operatore Null Coalescing
let operatoreNullC = opzioni.valore ?? "default"; // --> 0
L’operatore “optional chaining”
L’aspetto (e l’utilità) di questo operatore è molto simile al precedente. Sinceramente trovo difficile spiegarlo a parole, quindi andiamo direttamente a vedere in che circostanze è utile:
let nFile = opzioni.files && opzioni.files.length;
Qui vogliamo assegnare alla variabile nFile
la lunghezza della lista opzioni.files
. Però dobbiamo prima assicurarci che opzioni.files
esista e sia
un oggetto, altrimenti non potremo accedere alla sua proprietà length
, e questo genererà un errore che interromperà il codice.
Per questo motivo è stato introdotto l’operatore “optional binding”, che ha questo aspetto: ?.
Vediamo l’esempio precedente, con questo nuovo operatore:
let nFile = opzioni.files?.length;
Se opzioni.files
non è un oggetto, allora verrà ritornato il valore undefined
al posto di un errore.
Ecco altri possibili utilizzi:
// Se uno qualsiasi degli attributi indicati non è definito, o non è un oggetto, verrà ritornato il valore 'undefined'
let variabile = oggetto.figlio?.nipote?.pronipote?.proprietà;
// Esegue la funzione solo se esiste come attributo. Se esiste ma non è una funzione, verrà generato un errore.
oggetto.funzione?.();
// Esempio di come assegnare un valore di default: optional chaining + null coalescing
let variabile = oggetto.proprieta?.valore ?? "default";
Convertire qualsiasi cosa in un boolean: !!
Per convertire una variabile nel suo rispettivo valore booleano (true
o false
), possiamo usare la funzione
Boolean
:
let oggetto = {};
let valoreBool = Boolean(oggetto); // --> true
Se però questa sintassi sembra un po’ troppo pesante da leggere, possiamo semplificarla in questo modo:
let oggetto = {};
let valoreBool = !!oggetto; // --> true
Il primo !
(operatore NOT) esegue il typecasting della variabile al valore booleano contrario, per poi correggerlo con
il secondo !
:
"stringa"; // --> valore che, se convertito in boolean, è 'true'
!"stringa"; // --> false (valore opposto di quello che dovrebbe essere)
!!"stringa"; // --> true (invertiamo il valore per correggerlo)
Attenzione a fare questa cosa con un array vuoto! Se convertiano in boolean un array vuoto, otterremo true
, ma se
confrontiamo il nostro array con il valore false
, verranno considerati uguali.
Questo succede perché ogni valore ha la proprietà di essere un valore “falso” o “vero”. Un oggetto (Array e simili compresi) è sempre un valore “vero”.
Quando però lo si mette a confronto con un valore di tipo diverso, al posto di controllare se la variabile è “vera” o “falsa”,
viene fatto un typecasting (conversione del tipo della variabile). Quando viene messo a confronto con il valore false
, javascript
trasforma prima l’Array in una stringa, e poi trasformerà la stringa nel valore booleano. Un Array vuoto verrà trasformato in una stringa
vuota, che verrà trasformata nel valore false
.
let arr = [];
!!arr; // --> true
// Se 'arr' è true, ci aspetteremmo che questo controllo fallisca, invece...
if (arr == false) {
// Questo codice verrà eseguito comunque, perché l'array viene trasformato in questo modo:
// [] --> "" --> false
// Per trasformare l'array in una stringa, viene utilizzata la funzione Array.toString()
console.log("[] è uguale a false.");
}
if (arr) {
// Anche questo verrà eseguito, perché, se preso in considerazione da solo, l'array è un valore "vero":
// [] --> true
console.log("[] viene considerato 'true', perché è un oggetto.");
}
Concatenare delle espressioni
Ogni tanto può tornare utile eseguire più espressioni una dopo l’altra, dove generalmente non sarebbe possibile. Pensiamo a posti come l’inizializzazione di una variabile in un for, o una funzione a freccia senza parentesi graffe.
Ora vediamo alcuni modi per concatenare delle espressioni in javascript, e vediamo anche che valore verrà ritornato da ognuno di essi.
Usando la virgola: epsressione1 , espressione2
Se usiamo la virgola, possiamo concatenare diverse espressioni e il valore che verrà ritornato è il risultato dell’ultima espressione della lista:
// ------------------ ( espressione1 , espressione2 )
let mapFunc = el => (console.log(el), (el += 1));
let arr = [0, 1, 2];
arr = arr.map(mapFunc); // Stamperà sulla console i valori, e poi li incrementerà di uno
Usando l’operatore OR
Come abbiamo visto prima, possiamo concatenare dei valori utilizzando l’operatore OR (||
). Appena una
di queste espressioni verrà valutata come “vera”, il suo valore verrà ritornato. Se non ci sono espressioni
che hanno true
come risultato, allora verrà ritornato il risultato dell’ultima espressione.
let valore = false || "" || "vero" || true;
console.log(valore); // --> "vero"
L’ultimo valore, true
, viene ignorato, perché un’espressione precedente è risultata veritiera.
Usando l’operatore AND
Anche questo l’abbiamo accennato precedentemente. E’ molto simile all’operatore OR, ma smetterà di eseguire le espressioni appena ne troverà una “falsa”, ritornando il suo valore. Se non c’è un valore che può essere convertito in “false”, allora ritornerà il risultato dell’ultima espressione.
let valore = true && {} && 0;
// Dato che '{}' viene convertito in 'true', il valore assegnato sarà...
console.log(valore); // --> 0
Questa tecnica sarà molto familiare agli sviluppatori React, che la incontrano ogni volta che vogliono mostrare degli elementi JSX solo quando una condizione viene soddisfatta:
// ...
return (
<div>
{condizione && <div>Io comparirò solo se 'condizione' risulterà vera!</div>}
</div>
);
Oltre a questi, c’è anche l’operatore Null Coalescing, che abbiamo visto in precedenza.
Conclusione
Javascript è un linguaggio ricco di particolarità e di operatori. Anche se forse non userete queste tecniche ogni giorno nel vostro lavoro, sapere cosa sono e come funzionano potrà tornarvi molto utile!