W3docs

Capire la Conversione da Object a Primitivo in JavaScript

Scopri come JavaScript converte gli object in primitivi: i suggerimenti string, number e default, il metodo Symbol.toPrimitive e la catena di fallback toString/valueOf.

Introduzione alla Conversione da Object a Primitivo

In JavaScript, gli object sono valori di riferimento, ma molte operazioni si aspettano un primitivo (una string, un numero o un boolean). Quando scrivi obj + "", +obj, o `${obj}`, il linguaggio deve prima trasformare l'object in un primitivo prima di poter eseguire l'operazione. Questo processo è chiamato conversione da object a primitivo.

Questa guida spiega le regole seguite da JavaScript: i tre suggerimenti di conversione ("string", "number", "default"), il metodo Symbol.toPrimitive che ti permette di controllare la conversione, e la catena di fallback toString()/valueOf() usata quando Symbol.toPrimitive è assente.

Come Funziona la Conversione da Object a Primitivo

Non esiste un operatore che converta un object in un boolean — gli object sono sempre truthy in un contesto boolean. Quindi la conversione da object a primitivo produce sempre una string o un number, e JavaScript decide quale ottenere passando all'object un suggerimento:

  1. Prima cerca un metodo [Symbol.toPrimitive](hint). Se presente, viene chiamato e il suo valore di ritorno (che deve essere un primitivo) viene utilizzato.
  2. Se Symbol.toPrimitive è assente, JavaScript ricorre a toString() e valueOf(), chiamandoli in un ordine che dipende dal suggerimento.

Tratteremo il fallback in dettaglio più avanti. Prima, l'approccio moderno ed esplicito.

Esempio: Implementare Symbol.toPrimitive

javascript— editable

Spiegazione: L'object user definisce un unico metodo Symbol.toPrimitive che si ramifica in base al suggerimento. Un template literal richiede il suggerimento "string", la moltiplicazione richiede "number", e l'operatore binario + richiede "default". Restituire this.money per il caso default mantiene coerente l'aritmetica con + rispetto a *.

Capire i Suggerimenti di Conversione

Un suggerimento è una string che il motore passa per indicare all'object che tipo di primitivo preferisce l'operazione:

  • "string": il risultato deve essere una string — String(obj), `${obj}`, alert(obj), o un object usato come chiave di proprietà.
  • "number": è atteso un risultato numerico — +obj unario, obj * 2, obj - 1, obj < other, Number(obj), Math.round(obj).
  • "default": l'operatore va bene con entrambi i tipi e non sa quale richiedere. È più raro di quanto ci si aspetti, ma è importante: l'operatore binario + (che può significare sia addizione che concatenazione di string) usa "default", così come gli operatori di uguaglianza debole == / != quando confrontano un object con un numero o una string.

Una sorpresa comune: obj + "" non usa il suggerimento "string" — usa "default". Se gestisci solo "string" e "number", il ramo "default" è quello che viene eseguito per +.

Esempio: Gestire Diversi Suggerimenti

javascript— editable

Spiegazione: Qui l'object item gestisce tutti e tre i suggerimenti. Si noti l'ultima riga: poiché l'operatore binario + usa il suggerimento "default", item + '' esegue il ramo "default" — non il ramo "string" — producendo "Item: Chair, Price: 45". Questa è esattamente il tipo di sottigliezza che rende utile gestire ogni suggerimento in modo esplicito. Vedi anche operatori di confronto e operatori numerici.

Il Fallback toString / valueOf

Se un object non ha un metodo Symbol.toPrimitive, JavaScript usa la coppia di metodi più vecchia e sceglie un ordine in base al suggerimento:

  • Per il suggerimento "string": prova prima toString(), poi valueOf().
  • Per il suggerimento "number" o "default": prova prima valueOf(), poi toString().

In ogni caso viene usato il primo metodo che restituisce un primitivo; se un metodo restituisce un object, viene ignorato e si prova il successivo. Un object normale eredita Object.prototype.toString (che restituisce "[object Object]") e Object.prototype.valueOf (che restituisce l'object stesso, quindi viene ignorato) — ecco perché ({}) + "" è "[object Object]".

javascript— editable

Spiegazione: Senza Symbol.toPrimitive, il suggerimento "string" raggiunge toString() e restituisce "John", mentre i suggerimenti numerici e default raggiungono valueOf() e restituiscono 1000. Symbol.toPrimitive è preferibile per il codice nuovo perché offre un unico punto esplicito per gestire ogni suggerimento; toString/valueOf rimangono utili quando ti interessa solo una direzione.

Buone Pratiche per Usare toPrimitive

Implementare Symbol.toPrimitive in modo efficace richiede chiarezza, coerenza e test approfonditi per assicurarsi che gli object si comportino in modo prevedibile quando vengono convertiti in primitivi. Ecco come applicare queste buone pratiche quando si usa il metodo Symbol.toPrimitive:

1. Semantica Chiara

Buona Pratica: Definisci Symbol.toPrimitive in modo chiaro per rendere le conversioni degli object prevedibili e comprensibili. Questo implica gestire esplicitamente i diversi tipi di suggerimenti di conversione ("string", "number" e "default") e fornire valori di ritorno appropriati per ogni caso.

Esempio:

javascript— editable

Spiegazione: In questo esempio, l'object dateEvent definisce chiaramente i comportamenti di conversione sia per i contesti string che number. Per le conversioni in string restituisce una descrizione, mentre per le conversioni in number restituisce il timestamp dell'evento. Questa distinzione chiara aiuta gli altri sviluppatori a capire cosa aspettarsi quando si converte l'object in contesti diversi.

2. Coerenza

Buona Pratica: Assicurati che le conversioni siano coerenti con i dati dell'object e il suo utilizzo previsto, evitando comportamenti confusi o illogici.

javascript— editable

Spiegazione: L'object product garantisce che la logica di conversione sia coerente con le sue proprietà. Che venga convertito in una string per la visualizzazione o in un numero per i calcoli, il risultato rimane intuitivo e utile, rispettando l'uso previsto di ogni proprietà.

3. Test

Buona Pratica: Testa accuratamente come si comportano i tuoi object in diversi scenari di conversione per evitare bug inaspettati nella tua applicazione.

Approcci di Test di Esempio:

  • Unit Test: Scrivi unit test che tentano di convertire l'object usando diverse operazioni (come operazioni aritmetiche, concatenazione di string, o passando l'object a funzioni che si aspettano un tipo primitivo) per assicurarsi che tutti gli scenari restituiscano i valori attesi.
// Note: In a browser environment, use console.assert or a test framework like Jest/Mocha.
// Assumes 'product' is defined as in the previous example.
console.assert(String(product) === "Laptop costs $1200", "String conversion failed");
console.assert(+product === 1200, "Number conversion failed");
console.assert(product + '' === "Laptop", "Default conversion failed");

Spiegazione: Tramite gli unit test, puoi verificare che l'object product gestisca correttamente tutte le forme di conversione secondo la logica specificata in Symbol.toPrimitive. Questo contribuisce a garantire affidabilità e coerenza nel modo in cui il tuo object interagisce con diverse parti del motore JavaScript e della tua applicazione.

Errori Comuni

  • Non esiste un suggerimento boolean. In un contesto boolean (if (obj), !obj, obj && x) l'object è sempre truthy e non viene mai convertito in un primitivo. La conversione da object a primitivo produce solo string e numeri.
  • + usa "default", non "string". Questo inganna molti sviluppatori: obj + "" attiva il suggerimento default. Anche confronti come obj == 5 usano "default".
  • Un metodo deve restituire un primitivo. Se Symbol.toPrimitive (o valueOf/toString) restituisce un object invece di un primitivo, si ottiene un TypeError. Per la coppia di fallback, restituire un object causa semplicemente l'omissione di quel metodo.
  • La conversione numerica di un risultato string può produrre NaN. Se il ramo "number"/"default" restituisce una string non numerica, i contesti che si aspettano un numero ottengono NaN: +{ [Symbol.toPrimitive]: () => "abc" } è NaN.

Conclusione

La conversione da object a primitivo è un meccanismo fondamentale di JavaScript che permette agli object di partecipare ad operazioni aritmetiche, concatenazione di string e operazioni di confronto. Il motore sceglie un suggerimento ("string", "number" o "default"), prova prima Symbol.toPrimitive, e altrimenti ricorre a toString()/valueOf(). Implementando Symbol.toPrimitive, ottieni un unico punto esplicito per controllare come si comporta un object personalizzato in ogni contesto — portando a codice più prevedibile e manutenibile. Per approfondire, consulta tipi di dato, tipi symbol e metodi degli object e this.

Esercitati

Pratica
Quando valuti obj + '' e obj ha un metodo Symbol.toPrimitive, quale suggerimento passa JavaScript?
Quando valuti obj + '' e obj ha un metodo Symbol.toPrimitive, quale suggerimento passa JavaScript?
Pratica
Se un object non ha un metodo Symbol.toPrimitive, in che ordine prova JavaScript per il suggerimento 'number'?
Se un object non ha un metodo Symbol.toPrimitive, in che ordine prova JavaScript per il suggerimento 'number'?
Was this page helpful?