Capire this, call, apply e bind in JavaScript

Guida Completa a this, call, apply e bind

Pubblicato:

Comprendere il `this` in JavaScript

In JavaScript, la keyword this è un identificatore speciale che si riferisce al contesto in cui una funzione viene eseguita. Determina il comportamento delle funzioni e a quale oggetto esse appartengono. In breve, this indica il contesto di utilizzo. Vedremo vari esempi per capire come this punti al contesto e come possa essere legato esplicitamente a un oggetto specifico o a una chiamata di funzione.

Cos'è `this`?

this fa riferimento all'oggetto da cui è stato invocato il metodo o la funzione in cui è utilizzato, ma il suo valore può variare a seconda del contesto di chiamata.

Contesti di `this`

Valore di this in Modalità Strict e Non-Strict

In modalità non-strict, this è sempre un riferimento a un oggetto. In modalità strict, invece, può essere qualsiasi valore.

Ecco un esempio che mostra come il valore di this cambia in base alla modalità:

// Modalità non-strict
function nonStrictFunction() {
  console.log(this); // window (o l'oggetto globale)
}
nonStrictFunction();

// Modalità strict
'use strict';
function strictFunction() {
  console.log(this); // undefined
}
strictFunction();

Contesto Globale

Nel contesto globale, this fa riferimento all'oggetto globale. In un browser, questo oggetto è window.

console.log(this); // window

All'interno di una Funzione

In una funzione non in modalità strict, this fa riferimento all'oggetto globale.

function globalFunction() {
  console.log(this); // window
}
globalFunction();

In modalità strict, this è undefined.

'use strict';
function strictFunction() {
  console.log(this); // undefined
}
strictFunction();

Metodi di un Oggetto

Quando this è utilizzato all'interno di un metodo di un oggetto, fa riferimento all'oggetto stesso.

const person = {
  name: 'John',
  greet: function() {
    console.log(this.name); // John
  }
};
person.greet();

Costruttori

Quando this è utilizzato all'interno di un costruttore, fa riferimento all'istanza dell'oggetto creato dalla funzione costruttore.

Utilizzando la sintassi della funzione costruttore:

function Person(name) {
  this.name = name;
}

const john = new Person('John');
console.log(john.name); // John

Utilizzando la sintassi della classe ES6:

class Person {
  constructor(name) {
    this.name = name;
  }
}

const john = new Person('John');
console.log(john.name); // John

Arrow Functions

Le arrow functions non hanno il proprio this. Invece, ereditano this dal contesto di esecuzione circostante al momento della loro creazione.

const person = {
  name: 'John',
  greet: () => {
    console.log(this.name); // undefined
  }
};
person.greet();

Nel caso sopra, this all'interno dell'arrow function fa riferimento al contesto globale, non all'oggetto person.

Comprendere i Metodi call, apply e bind in JavaScript

JavaScript offre tre metodi fondamentali per gestire il contesto (this) nelle funzioni:call(), apply() e bind(). Questi metodi permettono di modificare il contesto in cui una funzione viene eseguita, il che può essere particolarmente utile per controllare il comportamento delle funzioni.

call

Il metodo call consente di chiamare una funzione con un determinato valore di this e con una serie di argomenti passati singolarmente.

Sintassi

funzione.call(thisArg, arg1, arg2, ...)

Esempio

function saluta(saluto, punto) {
  console.log(saluto + ', ' + this.nome + punto);
}

const persona = { nome: 'Mario' };

saluta.call(persona, 'Ciao', '!'); // Output: Ciao, Mario!

//esempio 2
const car = {
  make: 'Toyota',
  model: 'Yaris',
  year: 2024
};

function describeCar(color, owner) {
  console.log(`${owner} owns a ${color} ${this.year} ${this.make} ${this.model}.`);
}

// Usa call per descrivere l'auto
describeCar.call(car, 'blue', 'Alice');

apply

Il metodo apply è simile a call, ma invece di passare gli argomenti singolarmente, li passiamo come un array o un oggetto simile a un array.

Sintassi

funzione.apply(thisArg, [arg1, arg2, ...])

Esempio

function saluta(saluto, punto) {
  console.log(saluto + ', ' + this.nome + punto);
}

const persona = { nome: 'Mario' };

saluta.apply(persona, ['Ciao', '!']); // Output: Ciao, Mario!

//esempio 2
const car = {
  make: 'Toyota',
  model: 'Yaris',
  year: 2024
};

function describeCar(color, owner) {
  console.log(`${owner} owns a ${color} ${this.year} ${this.make} ${this.model}.`);
}

const args = ['red', 'Bob'];

// Usa apply per descrivere l'auto
describeCar.apply(car, args);

bind

Il metodo bind crea una nuova funzione che, quando chiamata, ha il suo valore di this impostato su un determinato valore e, facoltativamente, ha una sequenza di argomenti preimpostati.

Sintassi

const nuovaFunzione = funzione.bind(thisArg, arg1, arg2, ...)

Esempio

function saluta(saluto, punto) {
  console.log(saluto + ', ' + this.nome + punto);
}

const persona = { nome: 'Mario' };

const salutaMario = saluta.bind(persona, 'Ciao');

salutaMario('!'); // Output: Ciao, Mario!

// esempio 2
const person = {
  firstName: 'John',
  lastName: 'Doe'
};

function logDetails(age, occupation) {
  console.log(`${this.firstName} ${this.lastName} is ${age} years old and works as a ${occupation}.`);
}

// Usa bind per creare una nuova funzione con this legato a person
const logJohnDetails = logDetails.bind(person, 30);

// Puoi ora chiamare la funzione con l'ultimo argomento
logJohnDetails('developer'); // Output: John Doe is 30 years old and works as a developer.

Quando usare call, apply e bind

  • Usa call quando vuoi eseguire immediatamente una funzione con un determinato valore di this e una serie di argomenti passati singolarmente.
  • Usa apply quando vuoi eseguire immediatamente una funzione con un determinato valore di this e un array di argomenti.
  • Usa bind quando vuoi creare una nuova funzione con un valore di this predefinito e, facoltativamente, argomenti predefiniti, per essere chiamata in un secondo momento.

Conclusione

Comprendere call, apply e bind è essenziale per padroneggiare il comportamento di this in JavaScript e per scrivere codice più flessibile e riutilizzabile. Utilizzando questi metodi, puoi controllare con precisione il contesto di esecuzione delle tue funzioni, migliorando la leggibilità e la manutenibilità del tuo codice.