Pregunta ¿Cuál es la diferencia entre llamar y aplicar?


¿Cuál es la diferencia entre usar call y apply invocar una función?

var func = function() {
  alert('hello!');
};

func.apply(); vs func.call();

¿Hay diferencias de rendimiento entre los dos métodos antes mencionados? Cuándo es mejor usar call encima apply ¿y viceversa?


2737
2017-12-31 19:56


origen


Respuestas:


La diferencia es que apply te permite invocar la función con arguments como una matriz; call requiere que los parámetros se enumeren explícitamente. Un mnemónico útil es "UN para unrray y do para doomma ".

Ver la documentación de MDN en aplicar y llamada.

Pseudo sintaxis:

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

También existe, a partir de ES6, la posibilidad de spread la matriz para su uso con el call función, puede ver las compatibilidades aquí.

Código de muestra:

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession +".");
}
theFunction("John", "fireman");
theFunction.apply(undefined, ["Susan", "school teacher"]);
theFunction.call(undefined, "Claude", "mathematician");
theFunction.call(undefined, ...["Matthew", "physicist"]); // used with the spread operator


3304
2017-12-31 20:00



K. Scott Allen tiene un buen escrito sobre el asunto.

Básicamente, difieren en cómo manejan los argumentos de función.

El método apply () es idéntico a call (), excepto que apply () requiere una matriz como segundo parámetro. La matriz representa los argumentos para el método de destino ".

Asi que:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);

209
2017-12-31 19:59



Para responder la parte sobre cuándo usar cada función, use apply si no conoce la cantidad de argumentos que aprobará, o si ya están en una matriz o un objeto similar a una matriz (como arguments objetar para enviar sus propios argumentos Utilizar call de lo contrario, ya que no es necesario ajustar los argumentos en una matriz.

f.call(thisObject, a, b, c); // Fixed number of arguments

f.apply(thisObject, arguments); // Forward this function's arguments

var args = [];
while (...) {
    args.push(some_value());
}
f.apply(thisObject, args); // Unknown number of arguments

Cuando no estoy pasando ningún argumento (como tu ejemplo), prefiero call ya que estoy vocación la función. apply implicaría que eres aplicando la función a los argumentos (inexistentes).

No debería haber diferencias de rendimiento, excepto tal vez si usa apply y envuelva los argumentos en una matriz (p. f.apply(thisObject, [a, b, c]) en lugar de f.call(thisObject, a, b, c)) No lo he probado, por lo que podría haber diferencias, pero sería muy específico del navegador. Es probable que call es más rápido si aún no tiene los argumentos en una matriz y apply es más rápido si lo haces.


150
2017-12-31 21:50



Aquí hay un buen mnemónico. UNpply usa UNrrays y UNsiempre toma uno o dos argumentos. Cuando usas dotodo lo que tienes que doapunta la cantidad de argumentos.


102
2017-09-04 13:36



Si bien este es un tema antiguo, solo quería señalar que .call es ligeramente más rápido que .apply. No puedo decirte exactamente por qué.

Ver jsPerf, http://jsperf.com/test-call-vs-apply/3


[UPDATE!]

Douglas Crockford menciona brevemente la diferencia entre los dos, lo que puede ayudar a explicar la diferencia de rendimiento ... http://youtu.be/ya4UHuXNygM?t=15m52s

¡Aplicar toma una serie de argumentos, mientras que Call toma cero o más parámetros individuales! Ah, ja!

.apply(this, [...])

.call(this, param1, param2, param3, param4...)


91
2017-11-07 17:36



Sigue un extracto de Cierre: la guía definitiva de Michael Bolin. Puede parecer un poco largo, pero está saturado con mucha información. Del "Apéndice B. Conceptos de JavaScript con frecuencia incomprendidos":


Qué this Se refiere a cuando se llama una función

Cuando se llama a una función de la forma foo.bar.baz(), el objeto foo.bar se conoce como el receptor. Cuando se llama a la función, es el receptor el que se usa como valor para this:

var obj = {};
obj.value = 10;
/** @param {...number} additionalValues */
obj.addValues = function(additionalValues) {
  for (var i = 0; i < arguments.length; i++) {
    this.value += arguments[i];
  }
  return this.value;
};
// Evaluates to 30 because obj is used as the value for 'this' when
// obj.addValues() is called, so obj.value becomes 10 + 20.
obj.addValues(20);

Si no hay un receptor explícito cuando se llama a una función, entonces el objeto global se convierte en el receptor. Como se explica en "goog.global" en la página 47, window es el objeto global cuando JavaScript se ejecuta en un navegador web. Esto lleva a un comportamiento sorprendente:

var f = obj.addValues;
// Evaluates to NaN because window is used as the value for 'this' when
// f() is called. Because and window.value is undefined, adding a number to
// it results in NaN.
f(20);
// This also has the unintentional side effect of adding a value to window:
alert(window.value); // Alerts NaN

Aunque obj.addValues y f se refieren a la misma función, se comportan de manera diferente cuando se llaman porque el valor del receptor es diferente en cada llamada. Por esta razón, cuando se llama a una función que se refiere a this, es importante asegurarse de que this tendrá el valor correcto cuando se llame. Para ser claro, si this no se hizo referencia en el cuerpo de la función, entonces el comportamiento de f(20) y obj.addValues(20) sería lo mismo

Como las funciones son objetos de primera clase en JavaScript, pueden tener sus propios métodos. Todas las funciones tienen los métodos call() y apply() que permiten redefinir el receptor (es decir, el objeto que this se refiere a) al llamar a la función. Las firmas de método son las siguientes:

/**
* @param {*=} receiver to substitute for 'this'
* @param {...} parameters to use as arguments to the function
*/
Function.prototype.call;
/**
* @param {*=} receiver to substitute for 'this'
* @param {Array} parameters to use as arguments to the function
*/
Function.prototype.apply;

Tenga en cuenta que la única diferencia entre call() y apply() es eso call() recibe los parámetros de la función como argumentos individuales, mientras que apply() los recibe como una única matriz:

// When f is called with obj as its receiver, it behaves the same as calling
// obj.addValues(). Both of the following increase obj.value by 60:
f.call(obj, 10, 20, 30);
f.apply(obj, [10, 20, 30]);

Las siguientes llamadas son equivalentes, como f y obj.addValues se refieren a la misma función:

obj.addValues.call(obj, 10, 20, 30);
obj.addValues.apply(obj, [10, 20, 30]);

Sin embargo, dado que ninguno call() ni apply() usa el valor de su propio receptor para sustituir el argumento del receptor cuando no está especificado, lo siguiente no funcionará:

// Both statements evaluate to NaN
obj.addValues.call(undefined, 10, 20, 30);
obj.addValues.apply(undefined, [10, 20, 30]);

El valor de this nunca puede ser null o undefined cuando se llama una función. Cuando null o undefined se suministra como el receptor a call() o apply(), el objeto global se usa como el valor para el receptor en su lugar. Por lo tanto, el código anterior tiene el mismo efecto secundario indeseable de agregar una propiedad llamada value al objeto global.

Puede ser útil pensar que una función no tiene conocimiento de la variable a la que está asignada. Esto ayuda a reforzar la idea de que el valor de esto estará vinculado cuando se llame a la función y no cuando se defina.


Fin del extracto


71
2017-12-04 12:41



A veces es útil para un objeto tomar prestada la función de otro objeto, lo que significa que el objeto prestado simplemente ejecuta la función prestada como si fuera suya.

Un pequeño ejemplo de código:

var friend = {
    car: false,
    lendCar: function ( canLend ){
      this.car = canLend;
 }

}; 

var me = {
    car: false,
    gotCar: function(){
      return this.car === true;
  }
};

console.log(me.gotCar()); // false

friend.lendCar.call(me, true); 

console.log(me.gotCar()); // true

friend.lendCar.apply(me, [false]);

console.log(me.gotCar()); // false

Estos métodos son muy útiles para dar a los objetos funcionalidad temporal.


33
2018-02-25 19:31



Otro ejemplo con Call, Apply y Bind. La diferencia entre Llamar y Aplicar es evidente, pero Enlazar funciona así:

  1. Bind devuelve una instancia de una función que se puede ejecutar
  2. El primer parámetro es 'esta'
  3. El segundo parámetro es un Separado por comas lista de argumentos (como Llamada)

}

function Person(name) {
    this.name = name; 
}
Person.prototype.getName = function(a,b) { 
     return this.name + " " + a + " " + b; 
}

var reader = new Person('John Smith');

reader.getName = function() {
   // Apply and Call executes the function and returns value

   // Also notice the different ways of extracting 'getName' prototype
   var baseName = Object.getPrototypeOf(this).getName.apply(this,["is a", "boy"]);
   console.log("Apply: " + baseName);

   var baseName = Object.getPrototypeOf(reader).getName.call(this, "is a", "boy"); 
   console.log("Call: " + baseName);

   // Bind returns function which can be invoked
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Output
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/

23
2018-03-31 07:32