call(), apply() y bind() son tres métodos que toda función JavaScript hereda de Function.prototype. Los tres permiten controlar manualmente el valor de this cuando se llama a una función. La diferencia está en cómo se pasan los argumentos y en si la función se ejecuta inmediatamente o se devuelve para usarla después.
call(): ejecutar con this y argumentos separados
call(thisArg, arg1, arg2, ...) llama a la función inmediatamente con el this que especifiques. Los argumentos se pasan uno por uno:
function presentar(saludo, puntuacion) {
console.log(`${saludo}, soy ${this.nombre}${puntuacion}`);
}
const persona = { nombre: 'Elena' };
presentar.call(persona, 'Hola', '!');
// "Hola, soy Elena!"
// Caso real: tomar prestado un método de otro objeto
const arrayLike = { 0: 'a', 1: 'b', 2: 'c', length: 3 };
const arr = Array.prototype.slice.call(arrayLike);
console.log(arr); // ['a', 'b', 'c']
apply(): como call() pero con array de argumentos
apply(thisArg, [args]) es idéntico a call() salvo que los argumentos se pasan como un array. Era muy útil antes de que existiera el spread operator:
function sumar(a, b, c) {
return a + b + c;
}
const numeros = [1, 2, 3];
// Con apply: pasar array como argumentos
console.log(sumar.apply(null, numeros)); // 6
// Hoy se prefiere spread:
console.log(sumar(...numeros)); // 6
// apply sigue siendo útil con Math.max/min:
const valores = [3, 1, 4, 1, 5, 9, 2, 6];
console.log(Math.max.apply(null, valores)); // 9
// O con spread:
console.log(Math.max(...valores)); // 9
bind(): crear una nueva función con this fijo
bind(thisArg, ...args) no ejecuta la función: devuelve una nueva función con el this permanentemente vinculado. Es la solución más limpia para el problema del callback:
const boton = {
texto: 'Enviar',
manejarClick() {
console.log('Clic en: ' + this.texto);
}
};
// Sin bind: this se pierde en el event listener
document.addEventListener('click', boton.manejarClick);
// "Clic en: undefined"
// Con bind: this siempre apunta a boton
document.addEventListener('click', boton.manejarClick.bind(boton));
// "Clic en: Enviar"
Partial application con bind()
Además de fijar this, bind() permite fijar argumentos de forma permanente, creando funciones especializadas (partial application):
function calcularPrecio(impuesto, precio) {
return precio * (1 + impuesto);
}
// Crear versiones especializadas con impuesto fijo
const conIva = calcularPrecio.bind(null, 0.21);
const conIvaReducido = calcularPrecio.bind(null, 0.10);
console.log(conIva(100)); // 121
console.log(conIvaReducido(100)); // 110
// En React es un patrón muy frecuente para pasar parámetros a handlers:
//
bind() no funciona con arrow functions
Las arrow functions no tienen su propio this, así que bind(), call() y apply() no pueden cambiar su contexto. El primer argumento (thisArg) se ignora:
const objeto = { valor: 42 };
const flecha = () => this.valor;
// bind no tiene efecto sobre el this de la arrow
const vinculada = flecha.bind(objeto);
console.log(vinculada()); // undefined (no 42)
// call tampoco:
console.log(flecha.call(objeto)); // undefined
El truco de slice.call para arrays
Antes de Array.from() y el spread operator, el patrón para convertir arguments en un array real era:
function ejemplo() {
// arguments es un objeto array-like, no un array
const args = Array.prototype.slice.call(arguments);
return args.map(x => x * 2);
}
console.log(ejemplo(1, 2, 3)); // [2, 4, 6]
// Hoy se usa rest parameters:
function ejemploModerno(...args) {
return args.map(x => x * 2);
}
La distinción práctica: usa call() cuando tienes los argumentos por separado, apply() cuando ya tienes un array y necesitas compatibilidad, y bind() cuando quieres crear una función para usar después o fijar argumentos parciales.
