🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Prototipi in JavaScript

Codegrind TeamAug 23 2024

In JavaScript, i prototipi sono alla base del sistema di ereditarietà e della creazione di oggetti. A differenza di molti altri linguaggi orientati agli oggetti che utilizzano classi per definire e creare oggetti, JavaScript si basa su un modello basato sui prototipi. Comprendere come funzionano i prototipi ti permette di sfruttare al massimo le potenzialità del linguaggio per scrivere codice modulare e riutilizzabile. In questa guida esploreremo cosa sono i prototipi, come funzionano e come puoi usarli efficacemente.

Cos’è un Prototipo?

In JavaScript, ogni oggetto ha un collegamento interno a un altro oggetto chiamato prototipo. Questo prototipo può essere visto come un modello o blueprint da cui l’oggetto eredita proprietà e metodi. Quando cerchi di accedere a una proprietà o a un metodo di un oggetto, JavaScript cerca prima nell’oggetto stesso. Se non trova la proprietà o il metodo lì, continua la ricerca nel prototipo dell’oggetto, e così via lungo la catena dei prototipi.

La Catena dei Prototipi

La catena dei prototipi è una sequenza di collegamenti tra oggetti che JavaScript percorre quando cerca una proprietà o un metodo. Se alla fine della catena non viene trovata la proprietà o il metodo richiesto, il risultato sarà undefined.

Esempio di Catena dei Prototipi

let oggetto = { nome: "Mario" };
console.log(oggetto.toString()); // Output: "[object Object]"

In questo esempio, toString() non è definito direttamente in oggetto, quindi JavaScript lo cerca nel prototipo, che in questo caso è Object.prototype, dove toString() è definito.

Creazione di Oggetti e Prototipi

Utilizzare un Oggetto come Prototipo

Un modo per creare un oggetto con un prototipo specifico è utilizzare Object.create(). Questo metodo crea un nuovo oggetto con il prototipo specificato.

Esempio di Object.create()

let prototipoAnimale = {
  saluta: function () {
    console.log("Ciao da " + this.tipo);
  },
};

let cane = Object.create(prototipoAnimale);
cane.tipo = "cane";
cane.saluta(); // Output: Ciao da cane

In questo esempio, cane eredita il metodo saluta dal prototipoAnimale.

Il Costruttore e il Prototipo

Un altro modo comune per creare oggetti e definire prototipi è utilizzare le funzioni costruttore. Ogni funzione costruttore ha una proprietà prototype, che viene utilizzata come prototipo per gli oggetti creati con new.

Esempio di Funzione Costruttore

function Persona(nome, eta) {
  this.nome = nome;
  this.eta = eta;
}

Persona.prototype.saluta = function () {
  console.log("Ciao, mi chiamo " + this.nome);
};

let mario = new Persona("Mario", 30);
mario.saluta(); // Output: Ciao, mi chiamo Mario

In questo esempio, Persona.prototype è il prototipo di tutti gli oggetti creati con new Persona. Il metodo saluta è condiviso da tutte le istanze di Persona.

Ereditarietà tra Prototipi

JavaScript consente agli oggetti di ereditare da altri oggetti tramite la catena dei prototipi. Questo permette di creare strutture di oggetti più complesse e riutilizzabili.

Esempio di Ereditarietà tra Prototipi

function Animale(tipo) {
  this.tipo = tipo;
}

Animale.prototype.saluta = function () {
  console.log("Ciao da un " + this.tipo);
};

function Cane(nome) {
  Animale.call(this, "cane"); // Eredita il costruttore di Animale
  this.nome = nome;
}

// Imposta il prototipo di Cane come un nuovo oggetto creato da Animale.prototype
Cane.prototype = Object.create(Animale.prototype);
Cane.prototype.constructor = Cane;

Cane.prototype.abbaia = function () {
  console.log(this.nome + " dice: Bau!");
};

let fido = new Cane("Fido");
fido.saluta(); // Output: Ciao da un cane
fido.abbaia(); // Output: Fido dice: Bau!

In questo esempio, Cane eredita da Animale, il che significa che tutte le istanze di Cane possono utilizzare sia i metodi definiti in Cane.prototype che quelli definiti in Animale.prototype.

Verifica delle Proprietà e dei Prototipi

hasOwnProperty()

Il metodo hasOwnProperty() viene utilizzato per verificare se una proprietà è presente direttamente sull’oggetto (non lungo la catena dei prototipi).

Esempio di hasOwnProperty()

let auto = {
  marca: "Fiat",
};

console.log(auto.hasOwnProperty("marca")); // Output: true
console.log(auto.hasOwnProperty("toString")); // Output: false (ereditato dal prototipo)

isPrototypeOf()

Il metodo isPrototypeOf() viene utilizzato per verificare se un oggetto è il prototipo di un altro.

Esempio di isPrototypeOf()

let animale = {
  tipo: "mammifero",
};

let gatto = Object.create(animale);
console.log(animale.isPrototypeOf(gatto)); // Output: true

instanceof

L’operatore instanceof verifica se un oggetto è stato creato da una specifica funzione costruttore (o eredita da essa).

Esempio di instanceof

function Persona(nome) {
  this.nome = nome;
}

let luca = new Persona("Luca");
console.log(luca instanceof Persona); // Output: true

Best Practices con i Prototipi

  • Evita di Sovrascrivere prototype: Modifica o estendi il prototipo, ma evita di sovrascriverlo completamente, poiché potresti perdere l’ereditarietà originale.

  • Usa Object.create() per Ereditarietà Semplice: Quando crei catene di prototipi, Object.create() è un modo chiaro e diretto per impostare il prototipo.

  • Utilizza le Classi ES6: Se stai lavorando in un ambiente che supporta ES6 o versioni successive, considera l’uso delle classi (class) per un’ereditarietà più chiara e strutturata.

Conclusione

I prototipi in JavaScript sono un concetto potente e fondamentale che permette di creare strutture di oggetti flessibili e riutilizzabili. Comprendere come funzionano i prototipi e come sfruttarli ti permetterà di scrivere codice più efficiente, modulare e mantenibile. Che tu stia utilizzando funzioni costruttore o le classi ES6, padroneggiare l’uso dei prototipi ti darà un vantaggio significativo nello sviluppo di applicazioni JavaScript avanzate.