Che cosa significa la keyword new in JavaScript?

Per capire che cosa significa la keyword new in JavaScript dobbiamo partire da molto lontano, ma ti assicuro che ne vale la pena. Pronto ad iniziare il viaggio?

Che cosa significa la keyword new in JavaScript?

JavaScript è un linguaggio di programmazione ad oggetti?

A giudicare da questo codice sembrerebbe di si:

La sintassi è molto simile a quella delle classi in altri linguaggi di programmazione, come Python o PHP.

E cosa dire della keyword new? Anche in Java (che è un linguaggio diverso da JavaScript) esiste qualcosa di simile e serve per instanziare nuovi oggetti a partire da una classe.

Tuttavia la keyword class in JavaScript è una “novità” del linguaggio introdotta con ES6 (2015).

In JavaScript infatti non esistono classi vere e proprie.

E la keyword new non instanzia oggetti nel vero senso della parola.

Quindi? Qual’è la verità?

Che cosa significa la keyword new in JavaScript? L’illusione delle classi in JavaScript

Per svelare il mistero mettiamoci nei panni di una sviluppatrice JavaScript alle prime armi: Laura.

Laura programma già in C++ ma si ritrova coinvolta in un nuovo progetto, questa volta scritto in JavaScript.

Ha poco tempo per studiare il linguaggio ed ogni giorno deve produrre codice, anche se al primo colpo non sarà l’implementazione perfetta.

Laura sa che in JavaScript non ci sono classi quindi evita di usare la keyword class perchè vuole prima vederci chiaro.

Laura si chiede: se la keyword class è stata aggiunta al linguaggio solo nel 2015, come abbiamo fatto finora a creare blocchi di funzionalità in JavaScript?

Fino a che …

Che cosa significa la keyword new in JavaScript? Need for speed

Un giorno Laura viene incaricata di creare una nuova funzionalità per l’applicazione che il team sta costruendo: una classe che crea “persone”, completa di metodi per modificarne il nickname.

Laura inizia a farsi alcune domande. Inizia a studiare un pò di documentazione e scopre che … le classi in JavaScript non sono altro che funzioni.

Per incapsulare dati e metodi in JavaScript, prima della keyword class non facevamo altro che usare funzioni.

Questo genere di funzioni si chiamano constructor functions in JavaScript, e servono a creare nuovi oggetti.

Con queste informazioni in mano Laura inizia a programmare in JavaScript le sue prime funzioni costruttore, ovvero funzioni che ritornano oggetti e metodi.

Una prima soluzione al compito di Laura potrebbe essere questa:

Il codice sembra funzionare come dovrebbe ma presto vengono fuori i problemi.

Sembra che i primi test sull’applicazione dimostrano che alla soglia dei 100 utenti (100 oggetti Person) il browser diventa lentissimo e va in crash.

JavaScript è un linguaggio per i browser: dobbiamo prestare molta attenzione alle performance.

Dopo una prima analisi con il team il responso è chiaro: la funzione Person non è ottimizzata.

Per ogni nuovo utente il motore JavaScript deve creare un nuovo oggetto . Ma oltre all’oggetto, il motore è costretto a creare il metodo changeNick 100 volte!

Svelato l’arcano! Come possiamo rendere questo codice più performante?

Che cosa significa la keyword new in JavaScript? Un legame nascosto tra oggetti

Laura tenta la strada più logica alla ricerca di una soluzione: separare il metodo changeNick dalla funzione Person.

Laura scopre infatti che può racchiudere tutti i metodi all’interno di un oggetto JavaScript.

Questo oggetto JavaScript poi può rimanere “collegato” a tutti gli oggetti di tipo Person, in modo che questi ultimi abbiano accesso ai metodi.

Ecco come sarebbe un primo refactoring del codice.

Creiamo prima di tutto un oggetto per contenere i metodi:

e poi facciamo qualche piccola modifica alla funzione Person:

Oh! Il codice sembra molto più pulito.

Ma la cosa più importante è che abbiamo spostato il metodo changeNick in un oggetto indipendente.

In questo modo il motore JavaScript non è più costretto a creare ogni volta la stessa funzione in memoria.

Ci sono anche alcune novità nel codice!

La più evidente è Object.create. Qual’è il suo ruolo?

Object.create è un metodo nativo di Object e fa due cose fondamentali:

  1. crea un legame dall’oggetto fornito come argomento verso un nuovo oggetto “figlio”
  2. ritorna il nuovo oggetto

In altre parole nel nostro codice l’oggetto newPerson rimane legato all’oggetto personMethods.

E da questo momento qualsiasi nuovo oggetto creato da Person può avere accesso ai metodi definiti in personMethods!

Com’è possibile? Indaghiamo meglio nelle prossima sezioni!

Che cosa significa la keyword new in JavaScript? JavaScript e gli oggetti

Se quindi in JavaScript non esistono classi vere e proprie qual’è il costrutto “primordiale” del linguaggio?

In Python ad esempio tutte le classi ereditano da una classe Object.

C’è qualcosa di simile in JavaScript, ma gli oggetti JavaScript sono semplici strutture dati di tipo chiave/valore:

Cosa ancora più sorprendente, alcuni dei sotto-tipi primitivi in JavaScript sono collegati ad un Object radice.

Le funzioni ad esempio in JavaScript sono oggetti.

Se creiamo una funzione e la ispezioniamo nella console del browser noteremo alcune cose davvero strane:

Output:

Da dove viene fuori il metodo toString?

Sorprendentemente anche Object ha un metodo chiamato toString.

Per qualche strano motivo la nostra funzione ha gli stessi metodi di Object!

Ma la cosa si fa ancora più strana se guardiamo a quanti metodi e proprietà sono direttamente collegati alla nostra funzione:

Che cosa significa la keyword new in JavaScript? JavaScript e i prototipi

Chi ha aggiunto questi metodi?

Abbiamo detto che anche le funzioni in JavaScript sono oggetti e questo può darci qualche indizio.

Forse function è un lontano “parente” di Object?

Bingo!

Object è il padre di tutti gli oggetti in JavaScript ma il meccanismo per cui ogni nuovo oggetto rimane collegato al “genitore” è abbastanza curioso.

Non si tratta di ereditarietà vera e propria come per i linguaggi OOP puri.

Ma occhio all’immagine sopra: tra le varie proprietà, quella che dovrebbe attirare di più la tua attenzione è prototype.

Che cosa significa la keyword new in JavaScript? JavaScript e i prototipi

Prototype è una parola strana, scelta per indicare un particolare oggetto JavaScript che viene automaticamente agganciato dal motore a qualsiasi altro oggetto.

Se proviamo infatti ad esplorare Object nel browser vedremo come il suo prototype non è altro che un oggetto, che contiene a sua volta diversi metodi:

Che cosa significa la keyword new in JavaScript? Object prototype

Ma perchè prototype è così importante in JavaScript?

Sfruttando prototype possiamo agganciare una sola volta il metodo changeNick a tutti gli oggetti creati da Person!

Rivediamo il codice:

La chiave di tutto? Object.create, che crea un link da newPerson verso personMethods.

Comprendere come funziona questo link tra oggetti in JavaScript è molto importante!

Ricorda semplicemente che se creo un nuovo oggetto con:

e chiamo il metodo changeNick sull’oggetto:

il motore JavaScript fa qualcosa del genere:

  1. cerca il metodo changeNick all’interno dell’oggetto me ma non lo trova e quindi inizia a risalire la catena dei prototipi
  2. individua il metodo changeNick sull’antenato di me, ovvero sull’oggetto personMethods
  3. esegue il metodochangeNick sull’oggetto me

Ma dov’è in tutto questo la keyword new di cui parlavamo a inizio sezione?

E come si usa esattamente prototype? Possiamo manipolarlo a mano?

Nel codice sopra non c’è traccia di prototype.

Abbiamo creato un link tra oggetti ma non nel modo ottimale.

Possiamo ripulire ancora il codice?

Che cosa significa la keyword new in JavaScript? Svelare il mistero di new

Se ricordi abbiamo visto che ogni oggetto JavaScript si ritrova automaticamente con una proprietà attaccata, chiamata prototype.

Abbiamo anche visto che prototype è a sua volta un oggetto, usato come bagaglio per contenere metodi a disposizione di tutti gli oggetti.

Che bisogno c’è quindi di creare personMethods, che è un contenitore di metodi, quando abbiamo già a disposizione prototype?

prototype e la keyword new sono la chiave per raggiungere il nirvana dell’OOP (seppure simulato) in JavaScript.

Se anteponiamo infatti la keyword new alla nostra funzione costruttore avremo quella che in gergo viene definita constructor call.

Ecco come può essere riscritto il codice di Laura:

La keyword new in JavaScript non è un altro che una sintassi più comoda per:

  1. ritornare automaticamente oggetti dalle funzioni costruttore; non c’è bisogno di return newPerson
  2. collegare i nuovi oggetti ad un prototype comune; non c’è bisogno di Object.create(personMethods)
  3. puntare nel modo corretto il this (su cui è in arrivo un post dettagliato!)

Ma la cosa più entusiasmante è il refactoring del codice di Laura.

Siamo infatti passati da una soluzione ingenua, che ogni programmatore JavaScript alle prime armi avrebbe elaborato:

passando per un primo refactoring, che usa timidamente i prototipi e il link tra oggetti:

fino ad arrivare alla soluzione ottimale, idiomatica e performante:

Basta quindi indagare un poco nei “misteri di JavaScript” per portare alla luce il mistero di new e prototype.

Che cosa significa la keyword new in JavaScript? In conclusione

Alla ricerca del segreto di new abbiamo fatto luce sull’illusione delle classi JavaScript.

In JavaScript non esistono classi nel vero senso del termine.

Quasi tutto è un oggetto.

Anche le funzioni stesse sono oggetti e possiamo utilizzare le constructor function come fabbriche per altri oggetti.

prototype infine è il jolly per agganciare metodi condivisi sui nostri oggetti.

Infine la keyword new: si tratta di una sintassi di convenienza per snellire la creazione ed il legame tra nuovi oggetti JavaScript.

Ma a differenza dei linguaggi OOP puri, new in JavaScript non “instanzia” nuovi oggetti a partire dalle classi.

new crea e collega: crea nuovi oggetti JavaScript, collegandoli l’uno all’altro, sfruttando il prototype.

Grazie per aver letto e alla prossima!