W3docs

Metodi Prototipo JavaScript Senza __proto__

Scopri i metodi moderni del prototipo JavaScript: Object.create(), getPrototypeOf(), setPrototypeOf() e come usare object senza prototipo come dizionari sicuri.

Ogni object JavaScript è collegato a un altro object chiamato il suo prototipo, e le ricerche di proprietà risalgono lungo quella catena. Il vecchio modo per leggere o modificare quel collegamento era la proprietà speciale __proto__, ma presenta problemi concreti: è un accessor ereditato (non uno slot di dati normale), si comporta in modo incoerente come chiave di object, e può essere sfruttato per corrompere gli object. Il JavaScript moderno lo sostituisce con metodi espliciti e prevedibili sul costruttore Object.

Questo capitolo mostra i metodi prototipo standard — Object.create(), Object.getPrototypeOf(), e Object.setPrototypeOf() — e gli helper di ispezione Object.keys(), Object.values(), Object.entries(), e Object.hasOwn(). Tratta poi il caso più utile per un object senza prototipo: un "dizionario" sicuro per chiavi arbitrarie.

Per una visione più ampia di come funziona la catena, vedi Ereditarietà prototipale e oltre.

Leggere e Impostare un Prototipo

Usa Object.getPrototypeOf() per leggere il prototipo di un object e Object.setPrototypeOf() per modificarlo. Questi sono i sostituti standardizzati per leggere e scrivere __proto__.

javascript— editable

Object.create(proto) costruisce un object completamente nuovo il cui prototipo è esattamente proto. È il modo più pulito per creare un object con un prototipo scelto senza usare affatto __proto__.

Perché Evitare __proto__

__proto__ è un getter/setter definito su Object.prototype, non una proprietà che risiede sul tuo object. Questa differenza causa due problemi pratici:

  • Può fallire o comportarsi in modo strano come chiave di dati. Poiché obj.__proto__ = value attiva il setter, non puoi memorizzare in modo affidabile una chiave con il nome letterale "__proto__" su un object ordinario — assegnare un non-object viene silenziosamente ignorato, e assegnare un object cambia il prototipo invece di aggiungere una chiave.
  • È una superficie di attacco nota ("prototype pollution"). Il codice che copia chiavi non attendibili su un object può essere ingannato facendolo scrivere su __proto__, inquinando Object.prototype per l'intero programma.

I metodi standardizzati sono espliciti riguardo all'intento: getPrototypeOf/setPrototypeOf modificano il prototipo, mentre le scritture normali di proprietà non lo toccano mai.

javascript— editable

Object Senza Prototipo

Object.create(null) crea un object il cui prototipo è null. Non eredita nulla — nemmeno toString, hasOwnProperty, o l'accessor __proto__.

javascript— editable

Il Problema del Dizionario che Risolve

Un pattern comune è usare un object semplice come mappa da chiavi string a valori. Il problema è che un {} semplice eredita già chiavi da Object.prototype, quindi chiavi fornite dall'utente come "constructor", "toString", o "__proto__" collidono con i nomi ereditati e rompono le ricerche.

javascript— editable

Un object con prototipo null non ha chiavi ereditate, quindi ogni chiave si comporta esattamente come scritto — incluso "__proto__":

javascript— editable

Per questo motivo gli object con prototipo null sono dizionari sicuri per chiavi non attendibili. (Il built-in Map è un'altra buona scelta e consente chiavi non-string.)

Aggiungere Metodi a un Object con Prototipo Null

Poiché non c'è nessun prototipo da cui ereditare, si assegnano i metodi direttamente come proprietà proprie.

javascript— editable

Iterare Chiavi, Valori ed Entries

Object.keys(), Object.values(), e Object.entries() restituiscono array delle proprietà enumerabili proprie di un object. In modo fondamentale, ignorano la catena del prototipo, quindi funzionano in modo identico su object normali e object con prototipo null. Vedi Object.keys, values, entries per ulteriori dettagli.

javascript— editable

Un avvertimento per gli object con prototipo null: non hanno toString ereditato, quindi passarne uno direttamente ai template literal o a String() genera un errore. Itera con gli helper Object.* (sopra) invece di fare affidamento sulla conversione automatica in string.

Verificare le Proprietà Proprie con Object.hasOwn()

Per verificare se una chiave è una proprietà propria dell'object (non ereditata), preferisci Object.hasOwn(). È il sostituto moderno di obj.hasOwnProperty() e funziona anche sugli object con prototipo null, che non hanno affatto un metodo hasOwnProperty.

javascript— editable

Composizione con Object.assign()

Quando vuoi che un object acquisisca il comportamento di altri, la composizione è spesso più chiara di una singola catena di ereditarietà: un object può avere solo un prototipo, ma Object.assign(target, ...sources) può incorporare metodi da molte fonti copiando le loro proprietà enumerabili proprie sul target.

javascript— editable

Object.assign() copia anche su un object con prototipo null, fornendo un dizionario composto senza superficie ereditata:

javascript— editable

Avvertimento copia superficiale: Object.assign() copia i valori delle proprietà, non cloni profondi. I valori object e array vengono copiati per riferimento, quindi la sorgente e il target condividono gli stessi object annidati.

javascript— editable

Per una copia profonda e indipendente usa invece structuredClone(source).

Best Practice

  • Usa i metodi standardizzati, non __proto__. Utilizza Object.create(), Object.getPrototypeOf(), e Object.setPrototypeOf(). Considera __proto__ un accessor legacy da evitare nel proprio codice.
  • Evita di cambiare i prototipi dopo la creazione. Impostare un prototipo scelto al momento della creazione con Object.create(proto) è più pulito e più facile da ragionare rispetto a mutarlo in seguito con Object.setPrototypeOf().
  • Usa Object.create(null) (o Map) per dizionari di chiavi non attendibili. Rimuove le chiavi ereditate e previene sorprese da prototype pollution.
  • Preferisci Object.hasOwn() a obj.hasOwnProperty(). È più breve, più sicuro da chiamare, e funziona sugli object con prototipo null.
  • Componi con Object.assign() quando hai bisogno di comportamento da più fonti — ricorda solo che è una copia superficiale.

Per materiale correlato, vedi Metodi Object e "this" e Flag e descrittori di proprietà.

Conclusione

I moderni metodi prototipo Object.* ti danno un controllo esplicito e prevedibile sulla catena del prototipo, sostituendo il bizzarro accessor __proto__. Object.create(null) produce un object pulito senza prototipo, ideale per dizionari, mentre Object.keys/values/entries, Object.hasOwn(), e Object.assign() ti permettono di ispezionare e comporre object in modo sicuro indipendentemente dal loro prototipo.

Esercizi

Pratica
Quale chiamata crea un object senza prototipo, rendendolo un dizionario sicuro per chiavi arbitrarie?
Quale chiamata crea un object senza prototipo, rendendolo un dizionario sicuro per chiavi arbitrarie?
Was this page helpful?