Menu

Tipi primitivi in JavaScript: i sette valori di base

I sette tipi primitivi di JavaScript (string, number, bigint, boolean, null, undefined, symbol) e in cosa si differenziano dagli oggetti.

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

Sette primitivi e tutto il resto

JavaScript divide i valori in due gruppi. Da una parte ci sono sette tipi primitivi: valori semplici e immutabili. Dall'altra ci sono gli oggetti: tutto ciò che è composto, mutabile o richiamabile. A livello di valori, questo è l'intero sistema dei tipi.

I sette primitivi:

Tutto ciò che non è in quell'elenco (array, funzioni, date, regex, semplici {}) è un oggetto. typeof ti dà il tipo a runtime, e noterai il famoso difetto nell'ultima riga. typeof null restituisce 'object' dal 1995 e non verrà mai corretto: troppo codice esistente si basa su questo comportamento.

Un primitivo è un valore, non un contenitore

Il modello mentale più utile: un primitivo è il suo valore. Il numero 3 non è una scatola che contiene 3, è semplicemente 3. Due variabili che contengono 3 contengono lo stesso valore, non due copie che puntano a qualcosa di condiviso:

I primitivi si confrontano per valore. Gli oggetti si confrontano per riferimento. Questa sola distinzione è la causa di molti momenti del tipo "perché questo è false?", soprattutto quando confronti array o oggetti con ===.

I primitivi sono immutabili

Non puoi modificare un primitivo. Ogni operazione che sembra una modifica in realtà produce un nuovo valore:

La prima chiamata costruisce una nuova stringa e la butta via, perché niente raccoglie il valore restituito. La seconda riassegna name. La stringa originale "ada" non è mai stata alterata, e non poteva esserlo. Lo stesso vale per i numeri: x + 1 produce un nuovo numero, non modifica x.

Per questo const su una stringa o un numero è davvero sicuro. Il valore non può cambiare, e const ti impedisce di riassegnare la variabile.

Number, BigInt e perché ce ne sono due

Il tipo number di JavaScript è un float a 64 bit. Questo significa aritmetica veloce e un tetto massimo: gli interi sono esatti solo fino a Number.MAX_SAFE_INTEGER (2^53 - 1):

Oltre quella soglia, gli interi iniziano a collidere. bigint esiste per gli interi che devono restare esatti a qualsiasi dimensione. Ne scrivi uno aggiungendo il suffisso n:

bigint e number non si mescolano nell'aritmetica: perderesti tutto il senso della precisione extra. Usa bigint quando lavori con ID di database, timestamp in nanosecondi o crittografia. L'aritmetica normale resta su number.

Anche le stringhe sono primitivi

Una stringa in JavaScript è un primitivo, non un oggetto, anche se espone metodi come .length, .slice, .toUpperCase:

Dietro le quinte, quando chiami un metodo su una stringa, JavaScript la avvolge per un attimo in un oggetto String per far funzionare la chiamata, poi butta via l'involucro. Non devi pensare a quell'involucro: ti basta sapere che le stringhe si comportano come valori (immutabili, confrontate per valore) anche se hanno una ricca serie di metodi.

Apici singoli, doppi apici e backtick creano tutti lo stesso tipo. I backtick permettono in più l'interpolazione e le stringhe su più righe, di cui parla la prossima pagina.

null e undefined

Due primitivi significano "nessun valore", e non sono intercambiabili.

undefined è ciò che ottieni quando qualcosa non è mai stato assegnato: una variabile dichiarata ma non inizializzata, un argomento di funzione mancante, una proprietà che non esiste:

null è ciò che scrivi tu quando vuoi dire "vuoto di proposito":

La convenzione di massima: undefined è il modo del linguaggio per dire "qui non c'è niente", null è il modo del programmatore. Entrambi sono falsy, entrambi falliscono l'uguaglianza con i valori normali, ed entrambi hanno più avanti una pagina dedicata.

Symbol: unici per costruzione

symbol è il primitivo meno usato. Ogni symbol che crei è unico, anche se due vengono costruiti con la stessa descrizione:

I symbol sono utili come chiavi di oggetti che non possono collidere con quelle esistenti: una libreria può attaccare metadati ai tuoi oggetti usando un symbol, con la certezza che nessun altro codice li sovrascriverà. Li incontrerai di nuovo con gli iteratori e con i symbol predefiniti come Symbol.iterator.

Controllare i tipi a runtime

typeof gestisce la maggior parte dei casi. Tieni a mente queste stranezze:

Per null, confronta direttamente: value === null. Per gli array, usa Array.isArray(value). Per sapere "è un primitivo qualsiasi?" non esiste un'unica funzione integrata, ma lo schema è abbastanza chiaro:

Primitivi e oggetti: la trappola dell'assegnazione

Un'ultima cosa da vedere prima di andare avanti. Dato che i primitivi sono valori e gli oggetti sono riferimenti, l'assegnazione si comporta in modo diverso:

Con i primitivi, b = a copia il valore. Con gli oggetti, y = x copia il riferimento: entrambi i nomi puntano allo stesso oggetto sottostante. Modificarlo attraverso un nome influisce sull'altro. Questa è la principale fonte di bug del tipo "aspetta, perché è cambiato?" in JavaScript.

Cosa ti porti a casa

  • Sette primitivi: string, number, bigint, boolean, null, undefined, symbol. Tutto il resto è un oggetto.
  • I primitivi sono immutabili e confrontati per valore; gli oggetti sono mutabili e confrontati per riferimento.
  • typeof ti dice il tipo a runtime, con due stranezze da ricordare: typeof null === "object" e typeof function === "function".
  • number è un float a 64 bit con un limite di sicurezza per gli interi; bigint esiste per gli interi esatti oltre quel limite.

Prossimo passo: stringhe e template literal

Le stringhe sono il primitivo che userai di più, e i template literal (quelle stringhe con i backtick) rendono semplice costruirle: interpolazione, testo su più righe, tagged template. È l'argomento della prossima pagina.

Domande frequenti

Quanti tipi primitivi ha JavaScript?

Sette: string, number, bigint, boolean, null, undefined e symbol. Tutto il resto (array, funzioni, date, oggetti semplici) è un oggetto. Puoi controllare il tipo di un valore a runtime con typeof, con l'unica stranezza storica che typeof null restituisce 'object'.

Qual è la differenza tra un primitivo e un oggetto in JavaScript?

I primitivi sono valori immutabili confrontati per valore: due 3 sono lo stesso 3. Gli oggetti sono mutabili e confrontati per riferimento: due {} sono distinti anche se sembrano identici. Assegnare un primitivo copia il valore; assegnare un oggetto copia il riferimento agli stessi dati sottostanti.

I primitivi di JavaScript sono davvero immutabili?

Sì. Non puoi modificare un primitivo sul posto: 'hello'.toUpperCase() restituisce una nuova stringa, non cambia l'originale. Riassegnare una variabile (x = x + 1) sostituisce il valore della variabile con un primitivo diverso; il valore originale non viene mai alterato. Per questo const name = 'Ada' ti permette comunque di costruire nuove stringhe a partire da name.

Perché typeof null restituisce 'object'?

È un bug dell'implementazione originale del 1995 che non è mai stato corretto perché troppo codice dipendeva da quel comportamento. Per controllare null, confronta con ===: value === null. Per controllare undefined, usa value === undefined oppure typeof value === 'undefined'.

Illustrazione dei linguaggi di programmazione di Coddy

Impara a programmare con Coddy

INIZIA