Metodi di Object in Javascript

Concetti Chiave
  • I metodi ereditati da Object.prototype sono disponibili per tutti gli oggetti in JavaScript.
  • Questi metodi includono toString(), toLocaleString(), valueOf(), e toJSON().
  • Questi metodi possono essere sovrascritti per fornire rappresentazioni personalizzate degli oggetti.
  • La serializzazione e deserializzazione degli oggetti in JSON avviene tramite i metodi JSON.stringify() e JSON.parse().
  • È possibile definire metodi personalizzati su oggetti per migliorare la loro rappresentazione e funzionalità.

Metodi di Object

Come discusso in precedenza, tutti gli oggetti JavaScript (eccetto quelli esplicitamente creati senza un prototipo) ereditano proprietà da Object.prototype.

Le proprietà ereditate attraverso questa modalità sono principalmente metodi, e poiché sono universalmente disponibili, sono di particolare interesse per i programmatori JavaScript. Abbiamo già visto i metodi hasOwnProperty() e propertyIsEnumerable(), per esempio. (E abbiamo anche già trattato diverse funzioni statiche definite sul costruttore Object, come Object.create() e Object.keys().) Questa sezione spiega una manciata di metodi di oggetto universali che sono definiti su Object.prototype, ma che sono destinati ad essere sostituiti da altre implementazioni più specializzate.

In questa lezione, mostriamo esempi di definizione di questi metodi su un singolo oggetto. Nelle lezioni sulle classi, vedremo come definire questi metodi più generalmente per un'intera classe di oggetti.

toString

Il metodo toString() non prende argomenti; restituisce una stringa che in qualche modo rappresenta il valore dell'oggetto su cui viene invocato. JavaScript invoca questo metodo di un oggetto ogni volta che ha bisogno di convertire l'oggetto in una stringa. Questo accade, per esempio, quando utilizziamo l'operatore + per concatenare una stringa con un oggetto o quando passiamo un oggetto a un metodo che si aspetta una stringa.

Il metodo toString() predefinito non è molto informativo (anche se è utile per determinare la classe di un oggetto, come vedremo). Per esempio, la seguente riga di codice restituisce semplicemente la stringa "[object Object]":

let s = { x: 1, y: 1 }.toString();

console.log(s);  // => "[object Object]"

Poiché questo metodo predefinito non mostra molte informazioni utili, molte classi definiscono le proprie versioni di toString(). Per esempio, quando un array viene convertito in una stringa, otteniamo una lista degli elementi dell'array, ciascuno a sua volta convertito in una stringa, e quando una funzione viene convertita in una stringa, otteniamo il codice sorgente per la funzione. Potremmo definire il nostro metodo toString() in questo modo:

let punto = {
    x: 1,
    y: 2,
    toString: function() {
        return `(${this.x}, ${this.y})`;
    }
};

// Usa toString() per convertire l'oggetto in una stringa
let s = String(punto);

console.log(s);  // => "(1, 2)"

toLocaleString

Oltre al metodo base toString(), tutti gli oggetti hanno un toLocaleString().

Lo scopo di questo metodo è restituire una rappresentazione stringa localizzata dell'oggetto. Il metodo toLocaleString() predefinito definito da Object non effettua alcuna localizzazione: semplicemente chiama toString() e restituisce quel valore. Le classi Date e Number definiscono versioni personalizzate di toLocaleString() che tentano di formattare numeri, date e orari secondo le convenzioni locali. Array definisce un metodo toLocaleString() che funziona come toString() tranne per il fatto che formatta gli elementi dell'array chiamando i loro metodi toLocaleString() invece dei loro metodi toString(). Si potrebbe fare la stessa cosa con un oggetto punto come questo:

let punto = {
    x: 1000,
    y: 2000,

    toString: function() { return `(${this.x}, ${this.y})`; },

    toLocaleString: function() {
        return `(${this.x.toLocaleString()}, ${this.y.toLocaleString()})`;
    }

};

// Stampa: "(1000, 2000)"
console.log(punto.toString());

// Stampa: "(1,000, 2,000)"
console.log(punto.toLocaleString());

Esistono tecniche più avanzate di localizzazione che possono essere utilizzate per formattare numeri e date in modo più sofisticato. Ne vedremo alcune in dettaglio nelle prossime lezioni.

valueOf

Il metodo valueOf() è molto simile al metodo toString(), ma viene chiamato quando JavaScript ha bisogno di convertire un oggetto in qualche tipo primitivo diverso da una stringa, tipicamente un numero.

JavaScript chiama questo metodo automaticamente se un oggetto viene utilizzato in un contesto dove è richiesto un valore primitivo. Il metodo valueOf() predefinito non fa nulla di interessante, ma alcune delle classi integrate definiscono il proprio metodo valueOf(). La classe Date, ad esempio, definisce valueOf() per convertire le date in numeri, e questo consente agli oggetti Date di essere confrontati cronologicamente con < e >.

Ad esempio, possiamo definire un metodo valueOf per un oggetto punto che restituisce la distanza dall'origine al punto:

let punto = {
    x: 3,
    y: 4,

    valueOf: function() {
        return Math.hypot(this.x, this.y);
    }
};

// n = 5
let n = Number(punto);
console.log(n);  // => 5

// Confronta i punti in base alla loro distanza dall'origine
let punto2 = { x: 6, y: 8 };
console.log(punto < punto2);  // => true

toJSON

Object.prototype non definisce effettivamente un metodo toJSON(), ma la funzione JSON.stringify(), che abbiamo visto nella lezione precedente, cerca un metodo toJSON() su qualsiasi oggetto che deve serializzare.

Se questo metodo esiste sull'oggetto da serializzare, viene invocato, e il valore di ritorno viene serializzato, invece dell'oggetto originale. La classe Date, che permette di rappresentare date, definisce un metodo toJSON() che restituisce una rappresentazione stringa serializzabile della data.

Ritornando al nostro esempio di oggetto punto, possiamo definire un metodo toJSON() che restituisce una stringa rappresentativa del punto:

let punto = {
    x: 1,
    y: 2,

    toString: function() {
        return `(${this.x}, ${this.y})`;
    },

    toJSON: function() {
        return this.toString();
    }
};

// Serializza l'oggetto punto in JSON
let s = JSON.stringify([punto]);

console.log(s);  // => '["(1, 2)"]'