this nelle Functions in Javascript

Mi sono imbattuto in un comportamento di JavaScript che voglio annotarmi. In particolare la differenza tra le funzioni tradizionali e le arrow functions sulla gestione del contesto di this. Questa differenza di comportamento influisce sulle operazioni asincrone e sui callback. Me ne sono accorto scrivendo questo codice:

constructor(scene, text_string) {
new FontLoader().load('fonts/helvetiker_regular.typeface.json', function (font) {
const geometry = text_geometry(font, text_string);
const mesh = new THREE.Mesh(geometry, fontMaterial);
scene.add(mesh);
this.mesh = mesh; // doesn't work, it's inside the scope of FontLoader()!
self.mesh = mesh; // Useless, this is a class member, not an instance member.
});
}

this è una parola chiave che viene legata dinamicamente in base al contesto in cui una funzione viene chiamata, non dove viene definita. Nell’esempio del codice sopra, viene utilizzata un’espressione di funzione tradizionale come callback per il metodo load. In questo caso, this all’interno del callback non si riferisce all’istanza della classe in cui il costruttore è definito, ma piuttosto al contesto in cui viene eseguito il callback, che probabilmente è il contesto globale o il contesto di FontLoader. Di conseguenza, l’assegnazione this.mesh = mesh non funziona come previsto.

Insomma da fuori (dall’istanza) mesh non era accessibile. Dunque mi sono detto, metto il mesh su una variabile di classe. Ma la conseguenza di questo comportamento è che quando istanziavo una nuova classe tutti gli update che effettuavo accedendo al membro mesh avevano effetto solo sull’ultima istanza, perché quella è una variabile di classe appunto, e non di istanza.

Non so se questa cosa fosse risolvibile in un altro modo. Ho scoperto che le arrow functions, introdotte in ES6, gestiscono la cosa in modo diverso. Non creano un proprio contesto this, ma catturano il valore di this del contesto circostante in cui la arrow function è definita. Nello snippet di codice che segue, viene utilizzata una arrow function come callback, quindi this all’interno del callback si riferisce correttamente all’istanza della classe, consentendo di impostare this.mesh come desiderato.

constructor(scene, text_string) {
new FontLoader().load('fonts/helvetiker_regular.typeface.json', (font) => {
const geometry = text_geometry(font, text_string);
const mesh = new THREE.Mesh(geometry, fontMaterial);
scene.add(mesh);
this.mesh = mesh;
});
}


La differenza tra le funzioni tradizionali e le arrow functions ha implicazioni significative quando si lavora con operazioni asincrone e callback. Le arrow functions sono spesso preferite come callback perché mantengono il contesto corretto di this, consentendo di accedere alle proprietà e ai metodi dell’istanza della classe in modo coerente.

Così quando sparo i numeri nel gioco che sto facendo per cercare di far fare i compiti di matematica a qualcuno, le operazioni che cercano di dar fuoco alla fenice vengono impostate e lanciate correttamente.