JavaScript Function bind()
Impara il binding delle funzioni in JavaScript: perché i metodi perdono `this` con setTimeout, come func.bind() risolve il problema e l'applicazione parziale.
In JavaScript, il valore di this all'interno di un metodo viene deciso al momento della chiamata della funzione, non quando viene scritta. Nel momento in cui si distacca un metodo dal suo object — passandolo come callback o a setTimeout — esso dimentica a quale object apparteneva. Il function binding è la soluzione: blocca permanentemente this su un object scelto, in modo che il metodo si comporti allo stesso modo indipendentemente da dove viene chiamato.
Questo capitolo tratta quando e perché this viene perso, come func.bind() lo risolve, come usare bind per l'applicazione parziale e come bind si confronta con le arrow function.
Il problema del "perdere this"
Un metodo funziona correttamente quando viene chiamato come object.method(), perché this viene impostato su tutto ciò che si trova a sinistra del punto. Ma passare lo stesso metodo altrove fa sparire il punto — e quindi this viene perso.
La seconda chiamata stampa Hello, undefined! perché runLater ha invocato callback() come funzione semplice, quindi this non è più user. (In strict mode this è undefined e leggere this.firstName lancerebbe un TypeError.)
La stessa cosa accade con setTimeout — memorizza la funzione e la chiama in seguito autonomamente, senza nessun object collegato:
Per saperne di più su come this viene risolto all'interno dei metodi, consulta Metodi degli object, "this".
Risolvere il problema con func.bind()
Il metodo func.bind(thisArg) restituisce una nuova funzione il cui this è impostato permanentemente su thisArg. La funzione originale non viene modificata — si ottiene una copia con il binding applicato.
Un pattern comune consiste nel salvare la versione con il binding direttamente sull'object, in modo che ogni riferimento sia sicuro da passare ovunque:
Il binding avviene una sola volta
Una volta che una funzione ha un binding, this è fissato per sempre. Chiamare bind di nuovo sul risultato non ha effetto — il secondo binding viene ignorato.
Applicazione parziale: impostare argomenti in anticipo
bind accetta argomenti dopo thisArg, e questi vengono passati alla funzione originale prima di qualsiasi argomento successivo. Ciò consente di creare una funzione specializzata a partire da una più generale — si chiama applicazione parziale.
È anche possibile impostare in anticipo sia this che gli argomenti insieme:
bind vs. arrow function
Una arrow function non ha un proprio this — eredita this dallo scope circostante nel momento in cui viene scritta (this lessicale). Questo le rende un'alternativa leggera a bind quando si ha bisogno di mantenere il this esterno all'interno di una callback:
Come scegliere:
- Usa una arrow function per catturare il
thiscorrente inline, specialmente nelle callback in cui non hai bisogno di una funzione separata e riutilizzabile. - Usa
bindquando hai bisogno di una funzione autonoma con unthisfisso da passare altrove, o quando vuoi anche impostare argomenti in anticipo. A differenza di un'arrow function, una funzione con il binding può essere memorizzata, riutilizzata e passata per nome.
Un avvertimento: una arrow function non può essere usata come metodo di un object che dipende da this che punta all'object stesso, perché cattura this dallo scope circostante (spesso l'object globale) invece che dal chiamante.
Quando usarlo?
- Passare un metodo a un gestore di eventi,
setTimeout/setInterval,Promise.then, o metodi degli array comeforEach. - Creare funzioni specializzate a partire da quelle generali tramite applicazione parziale (es.
bind(null, presetArg)). - In qualsiasi momento in cui un metodo deve continuare a funzionare dopo essere stato distaccato dal suo object.
Se hai bisogno di chiamare una funzione con un this scelto immediatamente (invece di creare una copia riutilizzabile), usa call/apply — vedi Decoratori e forwarding, call/apply. Per un'analisi più approfondita del this nelle arrow function, vedi Arrow function rivisitate.