Skip to main content

Метод Function.prototype.apply

Function.prototype.apply викликає функцію з явно вказаним контекстом (this), передаючи їй аргументи у вигляді масиву. Це «близький брат» методу call, і відрізняються вони тільки способом передачі аргументів.

Теорія

TL;DR

  • apply викликає функцію одразу і дозволяє вручну задати this.
  • Аргументи передаються масивом або масивоподібним об'єктом, а не через кому.
  • call робить те саме, але аргументи йдуть переліком через кому.
  • bind нічого не викликає: він лише повертає нову функцію з «прив'язаним» this.
  • Класичні застосування: Math.max.apply(null, nums) і «позичання» методів масиву для arguments.
  • Сучасна заміна в багатьох випадках: spread-синтаксис func(...args).

Швидкий приклад

javascript
function sum(a, b, c) { return a + b + c; } const numbers = [1, 2, 3]; // аргументи вже в масиві, тому apply підходить ідеально console.log(sum.apply(null, numbers)); // 6

Синтаксис

javascript
func.apply(thisArg, [argsArray])
  • thisArg це об'єкт, який стане this всередині функції;
  • argsArray це масив (або масивоподібний об'єкт) з аргументами.

Базове використання з явним контекстом:

javascript
function greet(city, job) { console.log(`Я ${this.name} з міста ${city}, працюю як ${job}`); } const user = { name: 'Maria' }; greet.apply(user, ['Kyiv', 'Frontend-розробник']); // Я Maria з міста Kyiv, працюю як Frontend-розробник

Те саме через call:

javascript
greet.call(user, 'Kyiv', 'Frontend-розробник');

Різниця тільки у способі передачі аргументів:

  • call -> через кому,
  • apply -> масивом.

Робота з масивоподібними об'єктами

apply часто застосовують, коли аргументи вже зберігаються в масиві або схожій структурі (arguments, NodeList тощо). Це дозволяє «позичити» метод масиву для об'єкта, у якого власних методів масиву немає:

javascript
function logArgs() { console.log(arguments); // перетворюємо arguments на масив за допомогою Array.prototype.slice const arr = Array.prototype.slice.apply(arguments); console.log(arr); } logArgs(1, 2, 3, 4); // arguments -> [1, 2, 3, 4]

Тут apply дає змогу викликати метод масиву (slice) на об'єкті arguments, який масивом не є, але має length і числові індекси.

Math.max і Math.min через apply

Методи Math.max і Math.min не приймають масив, лише перелік чисел. apply елегантно вирішує цю проблему:

javascript
const nums = [10, 20, 5, 40]; console.log(Math.max.apply(null, nums)); // 40 console.log(Math.min.apply(null, nums)); // 5

Аналог на ES6:

javascript
Math.max(...nums); // сучасний spread-синтаксис

apply проти call і bind

МетодЩо робитьЯк передаються аргументиКоли викликається
callВикликає функцію із заданим thisЧерез комуОдразу
applyВикликає функцію із заданим thisУ вигляді масивуОдразу
bindСтворює нову функцію з «прив'язаним» thisЧерез комуПізніше (під час виклику)

Підсумок по apply:

ВластивістьОпис
ПризначенняВикликати функцію із заданим this
Спосіб передачі аргументівМасив або масивоподібний об'єкт
Контекст виконанняГлобальний або заданий вручну
Коли використовуватиКоли аргументи вже зібрані в масив
Сучасна альтернативаfunc(...args) (spread-синтаксис)

Особливості thisArg

Якщо thisArg дорівнює null або undefined, то:

  • у строгому режимі ('use strict') -> this = undefined;
  • у нестрогому -> this = window (або global у Node.js).
javascript
function showThis() { console.log(this); } showThis.apply(null); // window (у нестрогому режимі)

Саме тому в прикладах на кшталт Math.max.apply(null, nums) перший аргумент безпечно ставлять null: контекст цим функціям не потрібен.

Типові помилки

  • Плутають call і apply. apply очікує один масив, тому sum.apply(null, 1, 2, 3) не спрацює, а sum.call(null, [1, 2, 3]) передасть масив як перший аргумент.
  • Думають, що apply повертає нову функцію. Її повертає bind; apply виконує функцію негайно і повертає її результат.
  • Розраховують на глобальний this у строгому режимі. У модулях і класах код виконується в строгому режимі, тому this при null залишиться undefined.
  • Передають у apply дуже великий масив. Кожен елемент стає окремим аргументом, тож на масивах у сотні тисяч елементів можна отримати RangeError: Maximum call stack size exceeded.
  • Намагаються створити об'єкт через apply. apply не працює з new: для виклику конструктора з масивом аргументів потрібні Reflect.construct(Ctor, args) або new Ctor(...args).

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.