В чем разница между call и apply в JavaScript?
Основное различие: форма передачи аргументов
Вы всё верно заметили. Ключевое отличие между call и apply — это способ передачи аргументов в вызываемую функцию после привязки контекста this:
func.call(context, arg1, arg2, ...)— аргументы передаются через запятую (по одному).func.apply(context, [arg1, arg2, ...])— аргументы передаются в виде массива (или массивоподобного объекта).
В остальном оба метода делают одно и то же: вызывают функцию с указанным значением this и заданными аргументами. В вашем примере:
user.greet.call(admin, 'Привет', '!'); // Аргументы: 'Привет', '!'
user.greet.apply(admin, ['Привет', '!']); // Аргументы: ['Привет', '!']
Результат будет идентичным: "Привет, Петр!".
Когда использовать call, а когда apply?
Выбор зависит от того, как вы получаете аргументы в момент вызова:
call— если количество аргументов известно заранее и их можно перечислить явно.apply— если аргументы уже находятся в массиве, или вы работаете с динамическим количеством параметров.
Пример с apply для динамических аргументов:
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
const numbers = [1, 2, 3, 4, 5];
console.log(sum.apply(null, numbers)); // 15
С call пришлось бы писать sum.call(null, 1, 2, 3, 4, 5) — неудобно, если массив формируется динамически.
Производительность
В современных движках JavaScript разница в производительности между call и apply пренебрежимо мала для 99% случаев. Однако есть нюанс: apply может быть чуть медленнее при очень большом количестве аргументов (больше 1000), так как движку нужно развернуть массив. Но на практике вы редко столкнетесь с такой ситуацией. Не стоит оптимизировать код, выбирая между call и apply — выбирайте тот, который делает код читаемее.
Современная альтернатива: spread-оператор
В ES6 появился spread-оператор (...), который позволяет использовать call с массивом аргументов:
user.greet.call(admin, ...['Привет', '!']); // Работает!
Это делает call более гибким. Некоторые разработчики предпочитают call + spread вместо apply, так как синтаксис выглядит чище. Другие остаются верны apply — это дело вкуса.
Практический совет
- Используйте
call, когда у вас есть фиксированный набор аргументов или вы используете spread-оператор. - Используйте
apply, когда у вас уже есть массив аргументов, и вы хотите подчеркнуть это в коде (например, при делегировании вызова).
В остальном — это синонимы. Главное — помните, что оба метода вызывают функцию немедленно, в отличие от bind, который создает новую функцию с привязанным контекстом.
Дополнение: работа с массивоподобными объектами
Есть еще одно важное различие, которое часто упускают из виду. apply принимает не только настоящие массивы, но и массивоподобные объекты (например, arguments внутри функции или объекты со свойством length). call так не умеет — он ожидает перечисление аргументов по одному.
Пример с arguments:
function logArgs() {
// arguments — массивоподобный объект
console.log.apply(console, arguments); // Работает!
// console.log.call(console, arguments) — не сработает как ожидалось
}
logArgs('a', 'b', 'c'); // Выведет: a b c
Также apply удобен, когда нужно передать аргументы из одной функции в другую без изменений. Например, паттерн "переадресация вызова":
function wrapper() {
// Дополнительная логика...
return originalFunction.apply(this, arguments);
}
С call такой трюк не пройдет, так как количество аргументов заранее неизвестно. Поэтому, если вы работаете с динамическими аргументами или массивоподобными объектами — выбирайте apply.
Ответов пока нет.
Войдите чтобы оставить ответ