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

Resuelto John Duff asked hace 14 años • 25 respuestas

¿ Cuál es la diferencia entre usar Function.prototype.apply()e Function.prototype.call()invocar una función?

const func = function() {
    alert("Hello world!");
};

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

¿Existen diferencias de rendimiento entre los dos métodos antes mencionados? ¿ Cuándo es mejor usar callover applyy viceversa?

John Duff avatar Jan 01 '10 02:01 John Duff
Aceptado

La diferencia es que applyte permite invocar la función argumentscomo una matriz; callrequiere que los parámetros se enumeren explícitamente. Un mnemotécnico útil es " A para matriz y C para coma ".

Consulte la documentación de MDN sobre solicitar y llamar .

Pseudo sintaxis:

theFunction.apply(valueForThis, arrayOfArgs)

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

También existe, a partir de ES6, la posibilidad de que spreadla matriz se use con la callfunción, puedes 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
Expandir fragmento

flatline avatar Dec 31 '2009 20:12 flatline

K. Scott Allen tiene un buen artículo sobre el tema.

Básicamente, difieren en cómo manejan los argumentos de las funciones.

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

Entonces:

// assuming you have f
function f(message) { ... }
f.call(receiver, "test");
f.apply(receiver, ["test"]);
notnoop avatar Dec 31 '2009 19:12 notnoop

Para responder la parte sobre cuándo usar cada función, use applysi no sabe la cantidad de argumentos que pasará, o si ya están en una matriz o en un objeto similar a una matriz (como el argumentsobjeto para reenviar sus propios argumentos). Úselo callde otra manera, ya que no es necesario envolver 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 paso ningún argumento (como en su ejemplo), prefiero callya que estoy llamando a la función. applyimplicaría que está aplicando la función a los argumentos (inexistentes).

No debería haber diferencias de rendimiento, excepto tal vez si usa applyy envuelve los argumentos en una matriz (por ejemplo, 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 callsea más rápido si aún no tiene los argumentos en una matriz y applyes más rápido si los tiene.

Matthew Crumley avatar Dec 31 '2009 21:12 Matthew Crumley

Aquí tienes una buena mnemónica. Aplicar utiliza matrices y siempre toma uno o dos argumentos. Cuando usas C all tienes que contar el número de argumentos.

Joe avatar Sep 04 '2013 13:09 Joe

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

Consulte 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

Apply 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...)

kmatheny avatar Nov 07 '2011 17:11 kmatheny

Sigue un extracto de Clausura: La guía definitiva de Michael Bolin . Puede parecer un poco extenso, pero está saturado de mucha información. Del "Apéndice B. Conceptos de JavaScript frecuentemente mal entendidos":


Qué thisse refiere cuando se llama a una función

Cuando se llama a una función de la forma foo.bar.baz(), el objeto foo.barse denomina receptor. Cuando se llama a la función, es el receptor el que se utiliza 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, la ventana es el objeto global cuando se ejecuta JavaScript 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.addValuesy fse 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, al llamar a una función que hace referencia a this, es importante asegurarse de que thistendrá el valor correcto cuando se llame. Para ser claros, si thisno se hiciera referencia a ellos en el cuerpo de la función, entonces el comportamiento de f(20)y obj.addValues(20)sería el mismo.

Como las funciones son objetos de primera clase en JavaScript, pueden tener sus propios métodos. Todas las funciones tienen métodos call()que apply()permiten redefinir el receptor (es decir, el objeto al que thisse refiere) al llamar a la función. Las firmas del 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 que 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 y fse obj.addValuesrefieren a la misma función:

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

Sin embargo, dado que ni call()ni apply()utiliza 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 thisnunca puede ser nullo undefinedcuando se llama a una función. Cuando nullo undefinedse proporciona como receptor a call()o apply(), el objeto global se utiliza como valor para el receptor. Por lo tanto, el código anterior tiene el mismo efecto secundario indeseable de agregar una propiedad denominada valueal objeto global.

Puede resultar ú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 this estará vinculado cuando se llame a la función en lugar de cuando se defina.


Fin del extracto.

Dominykas Mostauskis avatar Dec 04 '2013 12:12 Dominykas Mostauskis