Diferencias entre call, apply y bind

Como call, apply y bind controlan el valor de this y los argumentos al invocar funciones en JavaScript.

Las tres son metodos de Function.prototype que sirven para controlar de forma explicita el valor de this cuando invocas una funcion. La diferencia esta en cuando se ejecuta la funcion y como se pasan los argumentos.

Tabla comparativa

Metodo¿Ejecuta?ArgumentosDevuelve
callSi, inmediatamenteLista separada por comasResultado de la funcion
applySi, inmediatamenteArray unicoResultado de la funcion
bindNo, devuelve nueva funcionLista separada por comas (parciales)Funcion con this y args fijados

Mismo ejemplo, tres formas

Mismo this, distintas invocaciones

javascript
function presentar(saludo, signo) {
  return `${saludo}, soy ${this.nombre}${signo}`;
}

const ada = { nombre: 'Ada' };

presentar.call(ada, 'Hola', '!');         // 'Hola, soy Ada!'
presentar.apply(ada, ['Hola', '!']);      // 'Hola, soy Ada!'

const presentarseAda = presentar.bind(ada, 'Hola');
presentarseAda('!');                      // 'Hola, soy Ada!'

Cuando usar cada uno

  • call: cuando tienes los argumentos uno a uno y quieres ejecutar la funcion en el acto. Util para invocar metodos con un this distinto sin crear una nueva funcion.
  • apply: cuando los argumentos ya estan en un array. Antes era util para hacer spreading; hoy el operador ... lo cubre mejor en la mayoria de casos.
  • bind: cuando necesitas guardar una funcion lista para llamarse despues con un this fijo, por ejemplo un callback o un event handler. Tambien sirve para aplicacion parcial de argumentos.

Caso practico: tomar prestados metodos

Array.prototype.slice es el truco clasico para convertir objetos array-like (como arguments o un NodeList antiguo) en arrays reales.

Method borrowing

javascript
function listar() {
  return Array.prototype.slice.call(arguments);
}

listar(1, 2, 3); // [1, 2, 3]

Caso practico: event handler con bind

bind para handlers

javascript
class Contador {
  constructor() {
    this.valor = 0;
    this.incrementar = this.incrementar.bind(this);
  }

  incrementar() {
    this.valor += 1;
  }
}

const c = new Contador();
boton.addEventListener('click', c.incrementar); // this seguira siendo c

Resumen

  • call y apply invocan la funcion; bind solo crea una nueva.
  • call recibe argumentos sueltos; apply recibe un array.
  • En codigo moderno, bind sigue siendo el mas comun: los arrow functions o el operador spread suelen reemplazar a call / apply.

Referencias