Menu

Oggetti in JavaScript: proprietà e metodi

Come funzionano davvero gli oggetti in JavaScript: crearli, leggere e scrivere proprietà, aggiungere metodi e i pattern che mantengono leggibile il codice.

Questa pagina include editor eseguibili: modifica, esegui e vedi subito l'output.

Un oggetto è un contenitore di valori con un nome

Un array raggruppa i valori per posizione. Un oggetto li raggruppa per nome. Quando ciò che stai modellando ha parti con un'etichetta, come un utente con nome ed età o una richiesta con metodo e URL, la scelta giusta è un oggetto.

Il modo più breve per crearne uno è un oggetto letterale:

Ogni voce è una coppia chiave: valore. Sotto il cofano le chiavi sono stringhe (le virgolette sono facoltative per identificatori validi come name). I valori possono essere qualsiasi cosa JavaScript sappia rappresentare: numeri, stringhe, booleani, array, funzioni e persino altri oggetti.

La virgola finale dopo l'ultima voce va benissimo. La maggior parte dei team la lascia: così i diff restano puliti quando più avanti aggiungi una nuova proprietà.

Leggere e scrivere le proprietà

Ci sono due modi per accedere a una proprietà: la notazione con punto e quella con parentesi quadre.

La notazione con punto è più pulita ed è quella che userai di default. Le parentesi quadre servono quando la chiave è salvata in una variabile o quando non è un identificatore valido:

Leggere una proprietà che non esiste restituisce undefined, senza nessun errore:

Questo può nascondere in silenzio gli errori di battitura. Se vuoi un fallimento evidente, devi controllarlo esplicitamente.

Aggiungere ed eliminare proprietà

Gli oggetti sono sempre aperti: puoi aggiungere chiavi in qualsiasi momento.

E rimuoverle con delete:

delete è uno di quegli operatori che non userai tutti i giorni, ma quando devi eliminare del tutto una chiave (e non solo impostarla a undefined) è lo strumento giusto. Con user.email = undefined la chiave resta lì: "email" in user sarebbe ancora true.

Controllare se una proprietà esiste

Tre modi, ognuno con un significato leggermente diverso:

  • in controlla se la chiave esiste, comprese quelle ereditate dalla catena dei prototipi.
  • Object.hasOwn(obj, key) guarda solo le chiavi proprie dell'oggetto. Usalo quando vuoi ignorare ciò che è ereditato. Sostituisce la vecchia chiamata hasOwnProperty.
  • obj.key !== undefined di solito funziona, ma ti inganna se una proprietà è impostata esplicitamente a undefined.

Nel dubbio, usa Object.hasOwn: fa esattamente quello che di solito ti aspetti.

Metodi: funzioni che vivono negli oggetti

Una proprietà il cui valore è una funzione si chiama metodo. Esiste una sintassi breve per definirli dentro un oggetto letterale:

this dentro un metodo si riferisce all'oggetto su cui il metodo è stato chiamato, in questo caso user. È così che greet sa quale nome usare.

Una cosa a cui fare attenzione: le arrow function non hanno un proprio this, quindi sono la scelta sbagliata per i metodi che devono leggere altre proprietà dell'oggetto:

Usa la sintassi abbreviata dei metodi (greet() { ... }) per tutto ciò che tocca this. Le arrow function sono ottime come callback, non come metodi degli oggetti.

Oggetti annidati

Anche i valori possono essere oggetti, a qualsiasi profondità:

Per leggere una proprietà annidata basta concatenare gli accessi: user.address.city. Il problema: se un qualsiasi passaggio lungo la strada è null o undefined, ottieni un TypeError:

console.log(user.profile.city);
// TypeError: Cannot read properties of undefined (reading 'city')

L'optional chaining (user.profile?.city) è la soluzione moderna: restituisce undefined invece di lanciare un errore quando manca un anello. Più avanti in questo capitolo c'è una pagina dedicata.

Scorrere un oggetto

Quando devi percorrere tutte le chiavi di un oggetto, la famiglia Object.keys, Object.values e Object.entries è quello che ti serve:

Object.entries è il più utile: ti dà chiave e valore insieme e si abbina benissimo alla destrutturazione degli array.

Esiste anche il ciclo for...in, ma percorre anche le proprietà ereditate, cosa che di solito non vuoi:

for (const key in scores) {
  console.log(key);  // works, but includes inherited keys
}

Preferisci Object.keys / Object.entries, a meno che tu non voglia proprio le proprietà ereditate.

Sintassi abbreviate da conoscere

Due zuccheri sintattici che vedrai ovunque:

La forma abbreviata delle proprietà scatta quando il nome della variabile coincide con la chiave. Le chiavi calcolate (la forma [expr]) ti permettono di costruire i nomi delle proprietà in modo dinamico: utile quando scrivi funzioni che aggiornano un campo per nome.

L'uguaglianza tra oggetti è per riferimento

Questa cosa frega quasi tutti almeno una volta:

=== sugli oggetti controlla se entrambi i lati puntano allo stesso oggetto in memoria, non se hanno lo stesso contenuto. Due oggetti con proprietà identiche restano due oggetti diversi.

Per chiederti "hanno la stessa forma?" devi confrontare i campi a mano oppure usare una funzione di uguaglianza profonda. JSON.stringify(a) === JSON.stringify(b) è un controllo veloce e approssimativo che funziona con dati semplici, ma cede con qualsiasi cosa contenga funzioni, undefined o riferimenti circolari.

Gli oggetti sono mutabili anche con const

const blocca la variabile su un unico valore. Non congela l'oggetto a cui quel valore punta:

Se vuoi davvero l'immutabilità, Object.freeze(user) impedisce ulteriori modifiche (in modo superficiale: gli oggetti annidati restano mutabili). In pratica la maggior parte del codice si affida alle convenzioni più che a Object.freeze: tratta gli oggetti const come "non riassegnare questo binding" e gestisci l'immutabilità a livello di progettazione.

Prossimo passo: gli array

Oggetti e array sono i due mattoni con cui è costruito tutto il resto. Gli oggetti gestiscono dati con un'etichetta, gli array dati in ordine. Nella prossima pagina: come funzionano gli array in JavaScript e la manciata di metodi (push, slice, map e compagnia) che fanno la maggior parte del lavoro.

Domande frequenti

Come si crea un oggetto in JavaScript?

Il modo più comune è un oggetto letterale: const user = { name: 'Ada', age: 30 }. Le parentesi graffe contengono coppie chiave-valore separate da virgole. Le chiavi sono stringhe (le virgolette sono facoltative per gli identificatori validi) e i valori possono essere qualsiasi cosa: numeri, stringhe, array, funzioni, altri oggetti.

Che differenza c'è tra notazione con punto e con parentesi quadre?

user.name e user['name'] fanno la stessa cosa quando la chiave è un identificatore noto. Usa le parentesi quadre quando la chiave è salvata in una variabile (user[key]), contiene caratteri che la notazione con punto non sa interpretare (spazi, trattini) o inizia con una cifra. Per tutto il resto la notazione con punto è più pulita.

Come controllo se una proprietà esiste in un oggetto?

Usa 'name' in user per verificare la chiave, comprese quelle ereditate. Usa Object.hasOwn(user, 'name') per controllare solo le proprietà proprie dell'oggetto: è il sostituto moderno di hasOwnProperty. Anche user.name !== undefined funziona, ma ti inganna se la proprietà è impostata esplicitamente a undefined.

Come si scorre un oggetto in JavaScript?

for (const key in obj) itera sulle chiavi, comprese quelle ereditate. Più spesso si usano Object.keys(obj), Object.values(obj) o Object.entries(obj) con un ciclo for...of o .forEach(). Object.entries è comodo quando ti servono sia la chiave sia il valore nella stessa iterazione.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA