34

В чем разница между call и apply?

18

Вопрос: В чем разница между использованием Function.prototype.apply() и Function.prototype.call() для вызова функции?

Я имею следующий код:

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

Меня интересует разница между func.apply() и func.call().

Есть ли какие-либо различия в производительности между этими двумя методами? В каких случаях лучше использовать call вместо apply и наоборот?

5 ответ(ов)

1

Чтобы ответить на вопрос, когда использовать каждую функцию, используйте apply, если вы не знаете, сколько аргументов вы будете передавать, или если они уже находятся в массиве или массивоподобном объекте (например, объекте arguments для перенаправления ваших собственных аргументов). В противном случае используйте call, так как нет необходимости оборачивать аргументы в массив.

f.call(thisObject, a, b, c); // Фиксированное количество аргументов

f.apply(thisObject, arguments); // Перенаправление аргументов этой функции

var args = [];
while (...) {
    args.push(some_value());
}
f.apply(thisObject, args); // Неизвестное количество аргументов

Когда я не передаю никаких аргументов (как в вашем примере), я предпочитаю использовать call, поскольку я вызываю функцию. apply подразумевает, что вы применяете функцию к (несуществующим) аргументам.

Не должно быть значительной разницы в производительности, кроме, возможно, случаев, когда вы используете apply и оборачиваете аргументы в массив (например, f.apply(thisObject, [a, b, c]) вместо f.call(thisObject, a, b, c)). Я это не тестировал, поэтому могут быть различия, но это будет очень специфично для браузеров. Скорее всего, call будет быстрее, если у вас нет аргументов в массиве, а apply — если они есть.

1

Вот хороший мнемонический прием. Apply использует Arrays и Aлгоритмически принимает один или два аргумента. Когда вы используете Call, вам нужно Cчитать количество аргументов.

0

Хотя это старая тема, я хотел бы отметить, что .call немного быстрее, чем .apply. Я не могу точно сказать, почему это так.

Посмотрите на jsPerf, http://jsperf.com/test-call-vs-apply/3


[UPDATE!]

Дуглас Крокфорд кратко упоминает разницу между этими двумя методами, что может помочь объяснить различия в производительности... http://youtu.be/ya4UHuXNygM?t=15m52s

.apply принимает массив аргументов, тогда как .call принимает ноль или более отдельных параметров! Ах, вот в чем дело!

.apply(this, [...])

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

0

Иногда бывает полезно, чтобы один объект заимствовал функцию другого объекта, что означает, что заимствующий объект просто выполняет заимствованную функцию, как будто она является его собственной.

Пример кода:

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

Эти методы очень полезны для предоставления объектам временной функциональности.

0

В этом примере показано, как работают методы Call, Apply и Bind. Разница между Call и Apply очевидна, а Bind работает следующим образом:

  1. Bind возвращает экземпляр функции, который может быть выполнен.
  2. Первый параметр — это значение this.
  3. Второй параметр — это комма-разделенный список аргументов (как и в Call).
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 и Call выполняют функцию и возвращают значение

   // Также обратите внимание на разные способы получения прототипа 'getName'
   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 возвращает функцию, которую можно вызвать
   var baseName = Person.prototype.getName.bind(this, "is a", "boy"); 
   console.log("Bind: " + baseName());
}

reader.getName();
/* Вывод
Apply: John Smith is a boy
Call: John Smith is a boy
Bind: John Smith is a boy
*/

В этом коде reader.getName() демонстрирует различия в использовании Call, Apply и Bind. Восприятие этих методов может значительно упростить работу с контекстом функций и передачей аргументов.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь