В чем разница между call и apply?
Вопрос: В чем разница между использованием Function.prototype.apply()
и Function.prototype.call()
для вызова функции?
Я имею следующий код:
const func = function() {
alert("Hello world!");
};
Меня интересует разница между func.apply()
и func.call()
.
Есть ли какие-либо различия в производительности между этими двумя методами? В каких случаях лучше использовать call
вместо apply
и наоборот?
5 ответ(ов)
Чтобы ответить на вопрос, когда использовать каждую функцию, используйте 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
— если они есть.
Вот хороший мнемонический прием. Apply использует Arrays и Aлгоритмически принимает один или два аргумента. Когда вы используете Call, вам нужно Cчитать количество аргументов.
Хотя это старая тема, я хотел бы отметить, что .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...)
Иногда бывает полезно, чтобы один объект заимствовал функцию другого объекта, что означает, что заимствующий объект просто выполняет заимствованную функцию, как будто она является его собственной.
Пример кода:
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
Эти методы очень полезны для предоставления объектам временной функциональности.
В этом примере показано, как работают методы Call
, Apply
и Bind
. Разница между Call
и Apply
очевидна, а Bind работает следующим образом:
Bind
возвращает экземпляр функции, который может быть выполнен.- Первый параметр — это значение
this
. - Второй параметр — это комма-разделенный список аргументов (как и в
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
. Восприятие этих методов может значительно упростить работу с контекстом функций и передачей аргументов.
Сравнение: var functionName = function() {} против function functionName() {}
Установка значения по умолчанию для параметра функции в JavaScript
Проверка существования переменной в JavaScript (определена/инициализирована)
Что означает восклицательный знак перед функцией?
JavaScript: Знак плюс перед функциональным выражением