call проти apply
call і apply викликають функцію із явно вказаним контекстом this, і відрізняються тільки способом передачі аргументів: call бере їх через кому, а apply одним масивом. Результат виклику, момент виклику і поведінка this у них ідентичні.
Теорія
TL;DR
- Обидва методи викликають функцію одразу і повертають її результат.
- Перший аргумент в обох це
thisArg, тобто контекст виклику. call-> аргументи через кому:func.call(thisArg, arg1, arg2, arg3).apply-> аргументи масивом:func.apply(thisArg, [arg1, arg2, arg3]).- Аргументи відомі наперед ->
call; аргументи вже в масиві ->apply. - У сучасному JS обидва часто замінює spread-оператор:
func(...args).
Швидкий приклад
| Метод | Як передаються аргументи | Приклад виклику |
|---|---|---|
call | перелічуються через кому | func.call(thisArg, arg1, arg2, arg3) |
apply | передаються у вигляді масиву | func.apply(thisArg, [arg1, arg2, arg3]) |
function greet(city, job) {
console.log(`Я ${this.name} з міста ${city}, працюю як ${job}`);
}
const user = { name: 'Maria' };
// call: аргументи через кому
greet.call(user, 'Kyiv', 'Frontend-розробник');
// apply: аргументи масивом
greet.apply(user, ['Kyiv', 'Frontend-розробник']);Обидва виклики виведуть одне й те саме:
Я Maria з міста Kyiv, працюю як Frontend-розробник
Коли використовувати який
| Сценарій | Краще використати |
|---|---|
| Аргументи відомі заздалегідь | call |
| Аргументи вже знаходяться в масиві | apply |
Приклад із масивом аргументів:
function sum(a, b, c) {
return a + b + c;
}
const nums = [1, 2, 3];
// без apply довелося б розкладати масив вручну
console.log(sum.call(null, nums[0], nums[1], nums[2]));
// з apply просто передаємо масив
console.log(sum.apply(null, nums)); // 6Що довший масив, то помітніша перевага apply: розкладати десять елементів вручну через call неможливо, якщо довжина масиву заздалегідь невідома.
Сучасний аналог зі spread
У сучасних версіях JavaScript (ES6+) apply часто замінюють оператором spread:
const nums = [1, 2, 3];
console.log(sum(...nums)); // той самий результат, що й sum.apply(null, nums)Spread читається простіше і не вимагає штучного null як контексту. apply залишається доречним тоді, коли this справді треба підмінити, наприклад fn.apply(ctx, args), або в старому коді без підтримки ES6.
Підсумкова таблиця
| Властивість | call | apply |
|---|---|---|
Контекст (this) | Явно вказується першим аргументом | Так само |
| Передача аргументів | Через кому | Масивом |
| Що повертає | Результат функції | Результат функції |
| Чи викликає одразу | Так | Так |
| Сучасна альтернатива | Spread: func(...args) | Spread: func(...args) |
Типові помилки
- Передають масив у
call.sum.call(null, [1, 2, 3])віддасть масив як перший параметрa, і результат буде"1,2,3undefinedundefined", а не6. - Перелічують аргументи в
apply.sum.apply(null, 1, 2, 3)ігнорує все після другого параметра:applyчитає лише один масив. - Плутають їх із
bind.callіapplyвикликають функцію негайно, аbindтільки повертає нову функцію, яку треба викликати окремо. - Забувають про
thisArg. Перший аргумент обов'язковий за позицією: якщо контекст не потрібен, передаютьnull, а не пропускають його. - Чекають на різну продуктивність. Різниці по суті немає, вибір між
callіapplyце питання зручності, а не швидкості.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.