Articolo originale: The JavaScript `this` Keyword + 5 Key Binding Rules Explained for JS Beginners

La parola chiave di JavaScript this è uno degli aspetti del linguaggio più difficili da comprendere. Tuttavia è di importanza critica per la scrittura di codice JavaScript più avanzato.

In JavaScript, la parola chiave this ci consente di:

  • Riutilizzare funzioni in diversi contesti di esecuzione. Vale a dire che una funzione, una volta definita, può essere chiamata per oggetti diversi usando la parola chiave this.
  • Identificare l'oggetto nel contesto di esecuzione corrente quando chiamiamo un metodo.

La parola chiave this è strettamente associata  alle funzioni JavaScript. Quando si parla di this, la cosa fondamentale è capire dove viene chiamata una funzione, poiché non sappiamo a cosa si riferisca la parola chiave this fino a quando la funzione non viene invocata.

L'uso di  this può essere categorizzato in cinque diversi aspetti di binding (associazione). In questo articolo, esamineremo tutti e cinque gli aspetti con degli esempi.

Innanzitutto, Cos'è il Binding?

In JavaScript, un ambiente lessicale è il posto in cui viene fisicamente scritto il codice. Nell'esempio qui sotto, la variabile name dal punto di vista lessicale è all'interno della funzione sayName().

function sayName() {
  let name = 'someName';
  console.log('Il nome è, ', name);
 }

Un contesto di esecuzione fa riferimento al codice attualmente in esecuzione e tutto ciò che contribuisce a eseguirlo. Possono esserci molti ambienti lessicali a disposizione ma quello che è attualmente in esecuzione viene gestito dal contesto di esecuzione.

lexical
Lexical Environment vs Execution Context

Ciascun contesto di esecuzione contiene un record di ambiente. Quando il motore JavaScript esegue il codice, variabili e nomi di funzioni vengono aggiunti al record di ambiente.

Questo fenomeno è noto in JavaScript come binding. Il binding aiuta l'associazione degli identificatori (variabili e nomi di funzioni) con la parola chiave this per costituire un contesto di esecuzione.

Non preoccuparti se trovi questo concetto difficile da capire adesso. Ne avrai una migliore comprensione mano a mano che procediamo.

Regola #1: Come Funziona il Binding Implicito di JavaScript

Il binding implicito copre la maggior parte dei casi d'uso per quanto riguarda la parola chiave this.

Quando invochiamo un metodo di un oggetto, usiamo la notazione punto (.) per accedervi. Nel binding implicito, devi verificare l'oggetto adiacente al metodo in fase di invocazione. Questo determina a cosa viene associato this.

Esaminiamo un esempio per capire meglio.

let blog = {
    name: 'Tapas',
    address: 'freecodecamp',
    message: function() {
        console.log(`${this.name} ha un blog su ${this.address}`);
    }
};

blog.message();

Qui this viene associato all'oggetto blog. Lo sappiamo perché chiamiamo il metodo message() sull'oggetto blog. Pertanto this.name sarà Tapas e this.address sarà  freeCodeCamp e tali valori verranno stampati nella console.

Vediamo un altro esempio per capire meglio questo concetto:

 function greeting(obj) {
      obj.logMessage = function() {
          console.log(`${this.name} ha ${this.age} anni!`);
      }
  };

  const tom = {
      name: 'Tom',
      age: 7
  };

  const jerry = {
      name: 'jerry',
      age: 3
  };

  greeting(tom);
  greeting(jerry);

  tom.logMessage ();
  jerry.logMessage ();

In questo esempio abbiamo due oggetti,  tom e jerry. Abbiamo decorato (arricchito) questi oggetti con un metodo chiamato logMessage().

Nota che quando invochiamo tom.logMessage(), il metodo viene chiamato sull'oggetto tom. Pertanto this è associato all'oggetto tom e i valori stampati saranno tom e 7 (this.name equivale a tom e this.age in questo caso è  7). Lo stesso vale quando viene invocato jerry.logMessage().

Regola #2: Come Funziona In JavaScript il Binding Esplicito

Abbiamo visto che JavaScript crea un ambiente per eseguire il codice che scriviamo. Si occupa della creazione in memoria di variabili, funzioni, oggetti e così via nella fase di creazione. Successivamente esegue il codice nella fase di esecuzione. Questo ambiente speciale viene chiamato contesto di esecuzione.

Possono essercene molti di questi ambienti (contesti di esecuzione) in un'applicazione JavaScript. Ogni contesto di esecuzione opera indipendentemente dagli altri.

A volte, tuttavia, potremmo voler usare cose che si trovano in un altro contesto di esecuzione. Ecco quando entra in gioco il binding esplicito.

Nel binding esplicito chiamiamo una funzione con un oggetto quando la funzione è al di fuori del contesto di esecuzione di quell'oggetto.

Ci sono tre metodi molto speciali:  call(), apply() e bind() che ci aiutano a ottenere il binding esplicito.

Come Funziona il Metodo call() di JavaScript

Con il metodo call(), il contesto nel quale la funzione deve essere chiamata verrà passato come parametro a  call(). Vediamo come funziona con un esempio:

let getName = function() {
     console.log(this.name);
 }
 
let user = {
   name: 'Tapas',
   address: 'Freecodecamp'  
 };

getName.call(user);

Qui sopra il metodo call() viene invocato su una funzione chiamata getName(). La funzione getName() stampa semplicemente alla console il valore di this.name. Ma cosa rappresenta this qui? Questo dipende da cosa è stato passato al metodo call().

In questo caso this sarà associato all'oggetto user, in quanto lo abbiamo passato come parametro al metodo call(). Pertanto this.name dovrebbe avere il valore associato alla proprietà name dell'oggetto user, vale a dire Tapas.

Nell'esempio qui sopra abbiamo passato solo un argomento a call(). Tuttavia  possiamo passare molteplici argomenti a call(), in questo modo:

let getName = function(hobby1, hobby2) {
     console.log('A ' + this.name + ' piace ' + hobby1 + ' , ' + hobby2);
 }

let user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

let hobbies = ['Nuotare', 'Tenere un Blog'];
 
getName.call(user, hobbies[0], hobbies[1]);

Qui abbiamo passato diversi argomenti al metodo call(). Il primo argomento deve essere il contesto dell'oggetto nel quale la funzione deve essere chiamata. Gli altri parametri potrebbero essere semplicemente valori da usare.

In questo caso sto passando Nuotare e Tenere un Blog come due parametri della funzione getName().

Hai notato il punto dolente qui? Nel caso di call(), gli argomenti devono essere passati uno ad uno  – il che non è un modo intelligente di fare le cose!. Ecco quando il nostro prossimo metodo, apply(), entra in  gioco.

Come Funziona il Metodo apply() in JavaScript

Questo modo di passare argomenti al metodo call() può essere risolto usando un metodo alternativo chiamato apply(). Funziona esattamente come call(), ma ti consente di passare gli argomenti in modo più conveniente. Dai un'occhiata a questo codice:

let getName = function(hobby1, hobby2) {
     console.log('A ' + this.name + ' piace ' + hobby1 + ' , ' + hobby2);
 }
 
let user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

let hobbies = ['Nuotare', 'Tenere un Blog'];
 
getName.apply(user, hobbies);

Qui siamo in grado di passare un array di argomenti, il che è molto più conveniente rispetto al passarli ad uno ad uno.

Suggerimento: Quando hai solo uno o nessun valore di argomento da passare, usa call(). Quando hai diversi valori di argomento, usa apply().

Come Funziona il Metodo bind() di JavaScript

Il metodo bind() è simile al metodo call(), con una differenza: diversamente da call(), che chiama la funzione direttamente,  bind() ritorna una funzione completamente nuova che possiamo invocare.

let getName = function(hobby1, hobby2) {
     console.log('A ' + this.name + ' piace ' + hobby1 + ' , ' + hobby2);
 }

let user = {
   name: 'Tapas',
   address: 'Bangalore'  
 };

let hobbies = ['Nuotare', 'Tenere un Blog'];
let newFn = getName.bind(user, hobbies[0], hobbies[1]); 

newFn();

Qui getName.bind() non chiama la funzione getName() direttamente. Ritorna una nuova funzione, newFn che possiamo invocare come newFn().

Rule #3: Il Binding new di JavaScript

La parola chiave new è usata per creare un oggetto dalla funzione costruttore.

let Cartoon = function(name, character) {
     this.name = name;
     this.character = character;
     this.log = function() {
         console.log(this.name +  ' è un ' + this.character);
     }
 };

Puoi creare oggetti usando la parola chiave new in questo modo:

 let tom = new Cartoon('Tom', 'Gatto');
 let jerry = new Cartoon('Jerry', 'Topo');

Quando una funzione viene invocata con la parola chiave new, JavaScript crea un oggetto this interno (così: this = {}) nella funzione. Il this appena creato si associa all'oggetto in fase di creazione usando la parola chiave new.

Sembra complicato? Ok, esaminiamolo approfonditamente. Osserva questa riga:

let tom = new Cartoon('Tom', 'Gatto');

Qui la funzione Cartoon viene invocata con la parola chiave new . Quindi il this creato internamente sarà associato al nuovo oggetto creato qui, che è tom.

Regola #4: Binding dell'Oggetto Globale di JavaScript

Quale pensi che sarà il risultato del codice qui sotto? A cosa è associato this qui?

let sayName = function(name) {
    console.log(this.name);
};

window.name = 'Tapas';
sayName();

Se la parola chiave this non viene risolta con alcuno dei binding, implicito, esplicito o new, allora this viene associata all'oggetto globale window() .

Esiste un'eccezione, tuttavia, la modalità strict (strict mode) di JavaScript non consente questo binding predefinito.

"use strict";
function myFunction() {
  return this;
}

Nell'esempio qui sopra,  this è undefined.

Regola #5: Binding di un Evento HTML in JavaScript

Nei gestori di eventi HTML, this viene associato all'elemento HTML che riceve l'evento.

<button onclick="console.log(this)">Click Me!</button>

Questo è il risultato nella console del click sul pulsante:

"<button onclick='console.log(this)'>Click Me!</button>"

Puoi cambiare lo stile del pulsante al click dell'utente usando la parola chiave this, in questo modo:

<button onclick="this.style.color='teal'">Click Me!</button>

Tuttavia, fai attenzione quando chiami una funzione per gestire un clic del pulsante e usi this all'interno di quella funzione; ipotizziamo questo codice HTML.

<button onclick="changeColor()">Click Me!</button>

e questo codice JavaScript:

function changeColor() {
  this.style.color='teal';
}

Quanto sopra non funzionerà come atteso. Come abbiamo visto nella regola  4, in questo caso this sarà associato all'oggetto globale (in modalità non strict), laddove non esiste un oggetto style con il quale impostare il colore.

Riepilogo

Per riassumere,

  • In caso di binding implicito,  this viene associato all'oggetto adiacente all'operatore punto (.) quando si invoca il metodo.
  • In caso di binding esplicito, possiamo chiamare una funzione con un oggetto quando la funzione è al di fuori del contesto di esecuzione dell'oggetto stesso. I metodi call(), apply(), e bind() giocano un grosso ruolo qui.
  • Quando una funzione viene chiamata con la parola chiave new, la parola chiave this all'interno della funzione si associa al nuovo oggetto che si sta costruendo.
  • Quando la parola chiave  this non è risolta con alcuna dei binding, implicito, esplicito o new, allora this viene associato all'oggetto globale window(). Nella modalità strict di JavaScript, this sarà undefined.
  • Nei gestori di evento HTML,  this viene associato all'elemento HTML che riceve l'evento.

C'è un ulteriore caso nel quale  this si comporta in modo differente, vale a dire le funzioni freccia E6. Daremo uno sguardo a questo caso in un articolo successivo.

Spero che tu abbia trovato utile questo articolo. Ti potrebbero anche piacere:

Se hai apprezzato questo articolo, condividilo in modo che altri lo possano leggere. Puoi menzionarmi su Twitter (@tapasadhikary) nei tuoi commenti, oppure sentiti libero di seguirmi.