Conociendo call, apply & bind… para un mismo ejemplo!

Adriel Zárate
3 min readOct 15, 2017

--

Buscando comparación entre call, apply y bind me he topado con casos de uso de cada uno en situaciones diferentes. Y aunque al final parece que los tres métodos hacen lo mismo, me ha resultado confuso saber cómo y cuándo elegirlos.

El ejemplo básico de call es:

let objetoUno = {
valorUno: 'valor uno de objetoUno',
valorDos: 'valor dos de objetoUno',
retornarValores: function() {
return `${this.valorUno}, ${this.valorDos}`;
}
};
let objetoDos = {
valorUno: 'valor uno de objetoDos',
valorDos: 'valor dos de objetoDos'
};
let valoresObjDos = objetoUno.retornarValores.call(objetoDos); console.log(valoresObjDos); // "valor uno en objetoDos, valor dos en objetoDos"

Ok, sencillo. Y si ahora lo hacemos con apply

let valoresObjDos = objetoUno.retornarValores.apply(objetoDos); console.log(valoresObjDos); // "valor uno en objetoDos valor, dos en objetoDos"

No hay diferencia. El “objetoDos” que pasamos, trabaja de la misma manera para call y apply: indica a nuestro método retornarValores que tome a this desde el argumento, y no desde objetoUno, que es el objeto que lo contiene.

Lo que necesitamos es un mismo ejemplo donde cada método haga notar cuál es su función. Esta diferencia se hace visible cuando hacemos uso de un segundo argumento, más específicamente si lo que pasamos es un array.

Vamos a redefinir nuestros objetos de la siguiente manera:

let objetoUno = {
listaUno : [],
pushLista: function(...args) {
this.listaUno.push(...args);
}
};
let objetoDos = {
listaUno : [1,2,3],
listaDos : [4,5,6]
};

Bien, entonces lo que queremos hacer es agregar los elementos de objetoDos.listaDos a objetoDos.listaUno haciendo uso de objetoUno.pushLista()

Vamos con call:

objetoUno.pushLista.call(objetoDos, objetoDos.listaDos);console.log(objetoDos.listaUno); // [1, 2, 3, Array(3)]

Oh no! no es lo que queríamos. call envía el segundo argumento como lo que es, un array en este caso, y con objetoUno.pushLista() se agrega como el cuarto elemento a nuestra objetoDos.listaUno

Pero con apply

objetoUno.pushLista.apply(objetoDos, objetoDos.listaDos);console.log(objetoDos.listaUno); // [1, 2, 3, 4, 5, 6]

Ajá! apply envía cada elemento del array por separado, como si fuese una lista de argumentos. Podríamos imaginarlo (pero no escribirlo!) así:

objetoUno.pushLista.apply(objetoDos, objetoDos.listaDos[0],objetoDos.listaDos[1],objetoDos.listaDos[2]);

Y que hay de bind? Bueno, como vimos, con call y apply el método que llamamos se ejecuta instantáneamente: objetoUno.pushLista.apply o call y boom! obtenemos nuestro resultado. Con bind lo que obtenemos es la función resultante, para que podamos asignara a alguna variable y usarla luego cuando la necesitemos. Ejemplo:

objetoUno.pushLista.bind(objetoDos, objetoDos.listaDos);console.log(objetoDos.listaUno); // [1, 2, 3]

!?.. No era que devolvía la función?
Sí, devuelve la función, no la ejecuta. Entonces objetoDos.listaUno sigue siendo el valor original. Podríamos hacer dos cosas, una es ejecutarla en el momento, agregando “()” al final:

objetoUno.pushLista.bind(objetoDos, objetoDos.listaDos)();console.log(objetoDos.listaUno); // [1, 2, 3, Array(3)], como con call!

o bien asignarla a una variable para ejecutarla luego:

let pushBind = objetoUno.pushLista.bind(objetoDos, objetoDos.listaDos);pushBind();console.log(objetoDos.listaUno); // [1, 2, 3, Array(3)]

Conclusión

Hay muchos posts por la web donde podemos ver en detalle las características y alcances de call, apply y bind por separado. Pero leer sobre cada uno y después decir “ok, entonces se diferencian en que…” puede ser algo complicado si se ven por primera vez. Este post fue mi forma de entenderlos. La idea es estar preparados para verlos mejor de a uno, sin descuidar lo que nos ofrecen los demás.

--

--