В чем разница между 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. Восприятие этих методов может значительно упростить работу с контекстом функций и передачей аргументов.
Установка значения по умолчанию для параметра функции в JavaScript
Определение глобальной переменной в функции JavaScript
Как лучше реализовать необязательные параметры функций в JavaScript?
Передать дополнительный аргумент в функцию обратного вызова
Какой самый быстрый способ перебора свойств объекта в JavaScript?