Quiz: Delizie della destrutturazione
Sei unmaestro del destructuring?
O è la tua Sinfonia della Distruzione?
Questo quiz metterà alla prova la tua conoscenza del Destructuring in JavaScript: dalla sintassi “base” degli oggetti al destructuring annidato e ai valori di default. In più, domande bonus su TypeScript e i tipi inline!
Tuffati subito nel riscaldamento – dimostra le tue capacità di Destructuring! 👇
Cosa stamperà questo codice?
const person = { name: 'Dan Levy', location: 'Cape Town',};const { name, age } = person;console.log(`Name: ${name}, Age: ${age}`);La proprietà age non esiste su person, quindi age sarà undefined. Sicuramente non Infinity 😅
Questo produce:
Name: Dan Levy, Age: undefinedCosa farà questo codice?
const person = [ 'Dan Levy', 'Cape Town' ];const [ name, origin, age ] = person;console.log(`Name: ${name}, Age: ${age}`);La variabile age non è presente nell’array tuple, quindi sarà undefined.
Questo produce:
Name: Dan Levy, Age: undefinedChe ne dici di un po’ di destrutturazione annidata?
'use strict';const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first }, address: { city }, birth: { place },} = person;console.log( `First: ${first}, City: ${place}`,);La proprietà birth: { place } non esiste su person, quindi genererà un errore.
Una soluzione è fornire valori predefiniti per le proprietà annidate.
Quando si accede a proprietà annidate - attenzione - gli errori possono essere difficili da individuare. Inoltre i messaggi di errore variano tra browser e altre piattaforme, rendendo il debug un po’ più complicato.
In Chrome moderno: TypeError: Cannot read properties of undefined (reading 'place')
In Node, anche questo è un TypeError perché JavaScript tenta di destrutturare place da undefined prima che place venga letto.
La formulazione esatta varia tra browser e runtime.
Ora con alcuni valori predefiniti, cosa farà questo?
'use strict';const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' },} = person;console.log( `Hi ${first} from ${place}`,);La proprietà birth non esiste su person, quindi l’intero oggetto ha ancora bisogno di un valore predefinito, non solo la proprietà annidata. In pratica manca un valore predefinito = {}.
In questo modo si dice “se person.birth è undefined, allora place è Unknown”. Ma person.birth è undefined, quindi tenta di destrutturare undefined, il che genera un errore.
In modern Chrome: `TypeError: Cannot read properties of undefined (reading 'place')`
In Node, this is also a `TypeError` because JavaScript tries to destructure `place` from `undefined`.
Exact wording varies between browsers and runtimes.Cosa farà questo?
const person = { name: { first: 'Dan' }, address: { city: 'Denver' },};const { name: { first = 'Unknown' }, birth: { place = 'Unknown' } = {},} = person;
console.log( `Hi ${first} from ${place}`,);La proprietà birth non esiste su person, quindi ricade su un oggetto vuoto = {}. Questo consente di utilizzare il valore predefinito.
Ora, come parametri della funzione, cosa farà?
'use strict';function displayUser({ name = "Unknown", age = -1,} = { place: "Unknown" }) { console.log(`Hi ${name} from ${place}`);}displayUser({ name: "Dan" });Questa funzione estrae le proprietà name e age, usando i valori predefiniti se necessario. In questo caso, la chiave place nell’oggetto di default è solo rumore, non viene usata dentro displayUser().
La modalità strict non cambia nulla: leggere il binding non dichiarato place genera un ReferenceError.
Come vengono gestiti i valori undefined?
'use strict';function displayPlace({ name = "N/A", place = "N/A", age = -1,} = { place: "Unknown" }) { console.log(`${place}`);}displayPlace({ name: "Dan" });displayPlace({ name: "Dan", place: undefined });displayPlace({ name: "Dan", place: "Joburg" });La funzione displayPlace utilizzerà UNICAMENTE un oggetto predefinito se non viene passato alcun oggetto. Quindi, l’unico modo per ottenere il valore predefinito { place: "Unknown" } è chiamare la funzione senza argomenti displayPlace().
Un altro comportamento notevole è che passare undefined per place farà sì che venga usato il valore di default, un po’ simile al comportamento di JSON.stringify (ignora undefined, riconosce null).
Questo produce:
displayPlace() // UnknowndisplayPlace({ name: "Dan" }) // N/AdisplayPlace({ name: "Dan", place: undefined }) // N/ASimile al precedente… come viene gestito null?_
function displayPlace({ name = "N/A", place = "N/A", age = -1,} = { place: "Unknown" }) { console.log(`${place}`);}displayPlace({ name: "Dan", place: null });displayPlace({ name: "Dan", place: undefined });In questo caso, la proprietà place è impostata a null nella prima chiamata e a undefined nella seconda. Il valore predefinito per place viene usato solo se l’intero oggetto è mancante o undefined. I null arriveranno come null.
Ora in TypeScript… cosa farà questo?
'use strict';function displayPlace( { name = 'N/A', place = 'N/A', }: { name: string; place: string; age: number; },) { console.log(`${place}`);}displayPlace({ name: 'Dan', place: null });TypeScript segnala un errore perché place è tipizzato come string, ma la chiamata passa null. La chiamata omette anche la proprietà obbligatoria age.
Se ignori gli errori di tipo, eseguendo il codice verrà stampato null nella console.
Proviamo un po’ di rinomina/assegnazione…
'use strict';function displayPlace({ name = 'N/A', place: location = 'N/A',}: { name: string; place: string; age?: number;}) { console.log(`${location}`);}displayPlace({ name: 'Dan', place: 'Denver' });Questo stamperà Denver sulla console. La proprietà place viene rinominata in location nella firma della funzione. È un pattern comune (rinominare le proprietà durante la destrutturazione) quando si adattano strutture dati di terze parti.
Individua l’errore di tipo:
function greet({ name: {first = "N/A", last = "N/A"}, birth: {place = "N/A"} = {}, age = -1,}: { name: {first?: string, last?: string}; birth: {place?: string}; age: number;}) { console.log(`Hi ${first} ${last} from ${place}`);}greet({ name: {first: 'Dan'} });L’errore è nella firma della funzione greet. Le proprietà age e birth mancano nell’oggetto passato, quindi dovrebbero essere opzionali nella definizione del tipo.
Anche se la proprietà birth è destrutturata con un valore predefinito, la definizione del tipo richiede che sia presente. Per rendere una proprietà opzionale in TypeScript, devi usare l’operatore ?.
Nota che birth?: { place?: string } non è lo stesso di birth: { place?: string } | undefined.
Ora con assegnazione (nota le variabili f, l e p)
'use strict';function greet( { name: {first: f = "N/A", last: l = "N/A"}, birth: {place: p = "N/A"} = {}, age = -1, }: { name: {first?: string, last?: string}; birth?: {place?: string}; age?: number; }) { console.log(`Hi ${f} ${l} from ${place}`); // What will 👆 do?}greet({ name: {first: 'Dan', last: 'Levy'}, birth: {place: 'Cape Town'},});Un altro Errore! Stai iniziando a indovinare, vero?!
È difficile leggere i livelli di destrutturazione, con valori di default, assegnazione e tipi!
Non appena place viene riassegnato alla variabile p, non è più definito nello scope della dichiarazione console.log.
console.log(`Hi ${f} ${l} from ${place}`); // ❌// to:console.log(`Hi ${f} ${l} from ${p}`); // ✅