front-end javascript Intermediate 3 min

Prototype chain e ereditarietà in JavaScript

[[Prototype]], Object.create, __proto__ vs prototype, instanceof

· 676 parole

Crei un oggetto vuoto {} e puoi già chiamare .toString() o .hasOwnProperty(), metodi che non hai mai scritto. Da dove arrivano? MDN lo spiega con un unico meccanismo: ogni oggetto ha un collegamento interno a un altro oggetto, il suo prototipo, e se una proprietà non si trova sull'oggetto stesso, JavaScript la cerca lì.

E' come chiedere un'informazione in un ufficio con più sportelli in fila. Se lo sportello che hai davanti non sa risponderti, ti indirizza automaticamente a quello accanto, che magari è in grado di fornirti l'informazione che stai cercando, oppure ti manda a sua volta a quello successivo. La catena continua finché qualcuno non ti fornisce l'informazione richeista, o finché non c'è più nessuno sportello.

1. [[Prototype]]: il collegamento nascosto tra oggetti

MDN chiama questo collegamento [[Prototype]] (con le doppie parentesi quadre: è una proprietà interna, non accessibile direttamente col punto). Il prototipo è a sua volta un oggetto, quindi ha il proprio prototipo: questa sequenza di collegamenti è la prototype chain.

const persona = {
    saluta() {
        return "Ciao";
    }
};

const studente = Object.create(persona);

studente.nome = "Ada";

studente.saluta(); // "Ciao" -- non è su studente, trovato sul prototipo

studente.nome; // "Ada" -- questa è una proprietà diretta (own property)

Quando cerchi studente.saluta, JavaScript non lo trova su studente, risale al suo prototipo (persona) e lo trova lì. La catena termina sempre con un prototipo che vale null: è il segnale «basta, non c'è altro dietro».

Fonte: MDN Web Docs: «Object prototypes»: la catena termina quando si raggiunge un prototipo il cui valore è null.

2. __proto__ vs prototype: due parole simili, due cose diverse

MDN è netto: __proto__ e prototype non sono la stessa cosa.

  • __proto__ esiste su qualunque oggetto, ed espone il suo [[Prototype]] interno. È deprecato come proprietà da usare direttamente, MDN consiglia Object.getPrototypeOf() al suo posto ma resta utile per capire il meccanismo.
  • prototype esiste solo sulle funzioni. È l'oggetto che diventerà il [[Prototype]] (quindi il __proto__) di ogni istanza creata con new quella funzione.
function Persona(nome) {
    this.nome = nome;
}

Persona.prototype.saluta = function () {
    return `Ciao, sono ${this.nome}`;
};

const ada = new Persona("Ada");

ada.__proto__ === Persona.prototype; // true

ada.saluta(); // "Ciao, sono Ada"

prototype è lo stampo di una fabbrica di biscotti: appartiene alla fabbrica (la funzione), non ai singoli biscotti. __proto__ è invece l'impronta che quello stampo lascia su ogni biscotto (l'istanza): la prova visibile di quale stampo lo ha generato.

Fonte: MDN Web Docs: «Object.prototype.__proto__»: espone il valore di [[Prototype]]; «Object prototypes»: tutte le funzioni hanno una proprietà prototype, usata quando la funzione è chiamata come costruttore con new.

3. instanceof: verificare la presenza in catena

L'operatore instanceof verifica se la proprietà prototype di un costruttore compare da qualche parte nella prototype chain di un oggetto, non se l'oggetto è stato creato proprio con quel costruttore.

function C() {}

function D() {}

const o = new C();

o instanceof C; // true

o instanceof D; // false: D.prototype non è nella catena di o

D.prototype = new C(); // ora colleghiamo D a C

const o3 = new D();

o3 instanceof D; // true

o3 instanceof C; // true: C.prototype ora è nella catena di o3

MDN segnala anche un errore comune: se qualcuno ha assegnato manualmente il prototipo di un oggetto (senza passare da new), instanceof può risultare vero anche se l'oggetto non è mai passato per quel costruttore.

Fonte: MDN Web Docs: «instanceof»: verifica la presenza di constructor.prototype nella prototype chain dell'oggetto, il che di solito (ma non sempre) significa che l'oggetto è stato costruito con quel costruttore.

In sintesi

Termine Cos'è Da ricordare
[[Prototype]] Collegamento interno tra un oggetto e il suo prototipo La catena termina sempre a null
__proto__ Espone il [[Prototype]] su qualunque oggetto Deprecato: preferire Object.getPrototypeOf()
prototype Esiste solo sulle funzioni Diventa il __proto__ delle istanze create con new
instanceof Verifica se prototype è nella catena Non garantisce che l'oggetto sia nato da quel costruttore

L'ereditarietà in JavaScript non copia i metodi da un oggetto all'altro: li condivide attraverso questa catena di collegamenti. Capire dove finisce la catena e chi ha messo cosa lì dentro è la chiave per non essere sorpresi da un metodo che «spunta dal nulla», o da uno che manca inspiegabilmente.

Accedi o registrati per votare, salvare o commentare la pillola

Commenti (0)

Registrati per commentare, fare domande e proporre l'argomento della prossima pillola (oppure accedi se hai già un account).

Nessun commento. Sii il primo a scrivere qualcosa.

Pillole correlate