"El buen diseño es obvio. El gran diseño es transparente"
- Joe Sparano

Call, apply y bind en Javascript

5 minutos de lectura
Fecha: 22/6/2017

En primer lugar, hay un concepto que tenemos que tener claro, en javascript casi todo son objetos, todos los tipos primitivos excepto null y undefined se tratan como objetos.

Y por tanto, y tienen todas las características de los objetos, como es poseer métodos y propiedades.

Dicho esto pensemos por un momento en las funciones, estas también son objetos, cuando declaramos una función realmente creamos una instancia de la clase Function, instanciando esta clase el resultado es un objeto con sus propiedades y métodos.

Veamos un ejemplo

var nuevaFuncion = function(arg1, arg2){
  console.log("Mis argumentos son " + arg1 + " y " + arg2);
}

console.log(nuevaFuncion.name); 
// nuevaFuncion
console.log(nuevaFuncion.toString()); 
// código de la función

En este ejemplo podemos apreciar que las funciones tienen una propiedad llamada name que devuelve el nombre del función, en este caso «nuevaFuncion» y un método (los métodos no dejan de ser funciones que declaramos en un objeto para operar con ellos) que nos devuelve en un string todo el código de la función.

El hecho de que los tengan ya demuestra que son Objetos, de hecho podríamos ir más allá y aclarar que no solo una función es un instancia de Function, sino que a su vez Function es una instancia de Object.

Por lo tanto los métodos y propiedades declaradas o bien dentro de Object o bien dentro de Funcion estarán disponibles en nuestras funciones.En la imagen de la derecha podemos ver inspeccionando el código toda esta herencia dentro de nuestra función.

Si nos fijamos no solo tenemos disponible el método toString(), Call, apply y bind son otros 3 métodos que podemos usar y ahora que ya entendemos que hacen ahí vamos a aprender para que sirven.

Descripción de la imagen

Call, apply y bind en Javascript

Los métodos call, apply y bind en Javascript sirven para llamar a una función asignando un valor a ‘this’, aprende como se usan y en que se diferencian.

Para entender que hacen antes tenemos que saber que es ‘this’ y cuando se incluye. This es una variable que hace referencia al contexto de la función, es la manera de acceder a nuestra propia instancia. Notad que hablamos del contexto de la función, pero a lo que se accede es a la instancia, y además la instancia que usamos para llamar la función, se ve claro con un ejemplo, mira atentamente este código:

var persona = {
  nombre: "Javi",
  saludar: function() {
    var nombre = "Julio";
    console.log("Hola " + this.nombre + "!");
  }
};
 
persona.saludar(); //??
 
var otraPersona = {
  nombre: "Óscar",
  saludar: persona.saludar // referencia al método de persona
};
 
otraPersona.saludar(); //??

La pregunta esta clara, cuando ejecuto persona.saludar() y otraPersona.saludar() que devuelve en cada caso? En el primer caso devuelve «Hola Javi!» pues this.nombre no hace referencia a la variable que esta en el interior de la función sino a la instancia desde donde se llama que ‘persona’. Y si te estas preguntando porque digo que es una instancia y no un objeto es porque todos los objetos son instancias de Object.

Y ahora el más difícil todavía que devuelve otraPersona.saludar()? Devuelve «Hola Óscar!», y aquí es donde muchos se pierden, pero recapitulemos, no acabamos de decir que this accede a la instancia que usamos para llamar a la función? Pues esa instancia es otraPersona, simplemente mira lo que hay antes del último punto, esa es siempre la instancia que llama.

De manera que el método saludar en este segundo caso esta declarado en la instancia ‘persona’, pero es llamado desde la instancia ‘otraPersona’ y por eso el this apunta a esta.

Como antes decíamos call, apply y bind sirven para invocar funciones o métodos especificando el valor que tiene ‘this’.

Método call()

Aquí tenéis el enlace a w3schools de esta función por si quereis consultarlo.

Esta función puede recibir múltiples argumentos pero con la peculiaridad de que el primero de ellos será el objeto de donde va a extraer el ‘this’, veámoslo…

var persona = {
  nombre: "Javi",
  saludar: function() {
    var nombre = "Julio";
    console.log("Hola " + this.nombre + "!");
  }
};

var persona1 = {
  nombre: "Óscar",
};
var persona2 = {
  nombre: "Sergio",
};
var persona3 = {
  nombre: "Marcos",
}; 

persona.saludar.call(persona1); //Hola Óscar!
persona.saludar.call(persona2); //Hola Sergio!
persona.saludar.call(persona3); //Hola Marcos!

El resultado ha sido: Hola Óscar!, Hola Sergio! y Hola Marcos! de manera que cuando entro ejecuto el método saludar del objeto persona this estaba apuntando a las instancias que le pasamos como parámetro, en este caso solo teníamos uno, pero podría darse el caso de que tuviéramos varios si el método los requiere, un último ejemplo:

var persona = {
  nombre: "Javi",
  saludar: function(saludo, dia) {
    var nombre = "Julio";
    console.log(saludo + this.nombre + ", feliz " + dia + "!");
  }
};

var persona1 = {
  nombre: "Óscar",
};
var persona2 = {
  nombre: "Sergio",
};
var persona3 = {
  nombre: "Marcos",
}; 

persona.saludar.call(persona1, "Hola ", "lunes"); //Hola Óscar, feliz lunes!
persona.saludar.call(persona2, "Buenas tardes ", "martes"); //Buenas tardes Sergio, feliz martes!
persona.saludar.call(persona3, "Adiós ", "miercoles"); //Adiós Marcos, feliz miercoles!

Ahora la salida sería Hola Óscar, feliz lunes!, Buenas tardes Sergio, feliz martes!, Adiós Marcos, feliz miércoles! Sobran las explicaciones de para que sirven los otros parámetros.

Método apply()

Aquí tenéis el enlace a w3schools de esta función por si queréis consultarlo.

El método apply es prácticamente pero se diferencia en los argumentos, mientras que en call pasamos los argumentos auxiliares de la función como argumentos, en apply los pasamos todos juntos en un array. Dicho de otra manera los parámetros de call son de 1 ..n, y en apply son 1 o 2.

Para entender que es exactamente lo mismo pero pasando de maneras distintas los argumentos este sería el ejemplo anterior con ambas maneras.

var persona = {
  nombre: "Javi",
  saludar: function(saludo, dia) {
    var nombre = "Julio";
    console.log(saludo + this.nombre + ", feliz " + dia + "!");
  }
};

var persona1 = {
  nombre: "Óscar",
};
var persona2 = {
  nombre: "Sergio",
};
var persona3 = {
  nombre: "Marcos",
}; 

// CON CALL()
persona.saludar.call(persona1, "Hola ", "lunes"); //Hola Óscar, feliz lunes!
persona.saludar.call(persona2, "Buenas tardes ", "martes"); //Buenas tardes Sergio, feliz martes!
persona.saludar.call(persona3, "Adiós ", "miércoles"); //Adiós Marcos, feliz miércoles!

// CON APPLY()
persona.saludar.apply(persona1, ["Hola ", "lunes"]); //Hola Óscar, feliz lunes!
persona.saludar.apply(persona2, ["Buenas tardes ", "martes"]); //Buenas tardes Sergio, feliz martes!
persona.saludar.apply(persona3, ["Adiós ", "miércoles"]); //Adiós Marcos, feliz miércoles!

Ambos comparten que el primer argumento es el objeto que define el this…

Método bind()

Aquí tenéis el enlace a mozilla.org de esta función por si queréis consultarlo.

Aquí no se trata de un método para invocar una función sino de un método para hacer una copia de ella con el this que le definamos, algo que nos será bastante util.

La diferencia práctica con los métodos anteriores, call y apply ejecutan la función y retornan un resultado que podremos guardar, sin embargo con bind lo que se guarda no es un resultado sino la propia función, y la podremos ejecutar en el futuro.

var persona = {
  nombre: "Javi",
  saludar: function(saludo, dia) {
    var nombre = "Julio";
    console.log(saludo + this.nombre + ", feliz " + dia + "!");
  }
};

var otraPersona = {
  nombre: "Óscar",
};


// CON CALL()
var copia = persona.saludar.bind(persona1, "Hola ", "lunes"); 
copia() //Hola Óscar, feliz lunes!
persona1.nombre = "Luis";
copia() //Hola Luis, feliz lunes!

Como podemos apreciar dentro de la variable copia hemos asignado una función que es una copia del método saludar() del objeto persona pero establecemos que this esta apuntando a otraPersona. Ahora podemos ejecutar la función copiada y el resultado es el que actualmente tengan los objetos, ya que como acabamos de ver podemos modificarlos.

Hasta aquí el post sobre call, apply y bind en Javascript, espero que os resulte útil!