Apply: примеры (JAVASCRIPT)

Метод apply в JavaScript: полное руководство с примерами
Раздел: Функции, Контекст выполнения
apply(thisArg, argsArray): any

Основы метода apply

Метод apply() является встроенным методом объектов функций в JavaScript. Он позволяет вызвать функцию с заданным значением this и аргументами, предоставленными в виде массива или массивоподобного объекта.

Использование метода актуально в случаях, когда необходимо явно установить контекст выполнения функции или когда аргументы для вызова динамически формируются в виде массива.

Синтаксис метода: function.apply(thisArg, [argsArray])

  • thisArg: Значение, которое будет передано функции как контекст this. Если значение равно null или undefined, контекстом станет глобальный объект (в нестрогом режиме).
  • argsArray: Необязательный аргумент. Массивоподобный объект, определяющий аргументы, с которыми будет вызвана функция. Если передано значение null или undefined, функция вызывается без аргументов.

Возвращаемое значение: результат выполнения вызванной функции с указанным контекстом this и аргументами.

Базовые примеры использования

Пример 1: Вызов функции с указанием контекста.

function introduce(greeting) {
    return `${greeting}, меня зовут ${this.name}`;
}
const person = { name: 'Анна' };
console.log(introduce.apply(person, ['Привет']));
Привет, меня зовут Анна

Пример 2: Использование для передачи массива аргументов.

function sum(a, b, c) {
    return a + b + c;
}
const numbers = [5, 10, 15];
console.log(sum.apply(null, numbers));
30

Пример 3: Вызов без передачи аргументов (второй параметр null).

function getContext() {
    return this;
}
const myObj = { id: 1 };
console.log(getContext.apply(myObj, null) === myObj);
true

Похожие методы в JavaScript

В JavaScript существуют два других метода для вызова функций с указанием контекста: call() и bind().

  • call(thisArg, arg1, arg2, ...): Аналогичен apply(), но принимает аргументы для функции не в виде массива, а списком через запятую. Предпочтителен, когда количество аргументов известно заранее.
  • bind(thisArg, arg1, arg2, ...): Создает новую функцию, привязанную к указанному контексту и, опционально, начальным аргументам. Функция не вызывается немедленно. Используется, когда необходимо создать отложенный вызов или передать метод как callback с сохранением контекста.

Выбор между apply и call часто зависит от формы, в которой доступны аргументы для вызова: список или массив.

Аналоги в других языках программирования

Python: Используется метод __call__ или распаковка аргументов с помощью оператора *.

def introduce(greeting):
    return f'{greeting}, меня зовут {self.name}'

class Person:
    def __init__(self, name):
        self.name = name

person = Person('Алексей')
# Использование метода как callable
print(introduce.__get__(person, Person)('Здравствуй'))
# Альтернатива с распаковкой
args = ['Здравствуй']
print(introduce(person, *args))
Здравствуй, меня зовут Алексей

PHP: Существуют функции call_user_func_array и call_user_func.

function introduce($greeting) {
    return $greeting . ', меня зовут ' . $this->name;
}

class Person {
    public $name = 'Мария';
}

$person = new Person();
$func = [new Person(), 'introduce'];
echo call_user_func_array($func, ['Привет']);
Привет, меня зовут Мария

C#: Аналогичную функциональность можно достичь с помощью делегатов и метода DynamicInvoke.

Типичные ошибки

Ошибка 1: Передача непримитивного значения как thisArg в строгом режиме.

'use strict';
function foo() {
    return this;
}
console.log(foo.apply(123)); // Примитив не преобразуется в объект-обертку
123

Ошибка 2: Передача аргументов, не являющихся массивоподобным объектом.

function bar(a, b) {
    return a + b;
}
console.log(bar.apply(null, 'ab')); // Строка имеет индексы 0 и 1
console.log(bar.apply(null, {0: 1, 1: 2, length: 2})); // Работает
console.log(bar.apply(null, {x: 1, y: 2})); // Ошибка
ab
3
// TypeError: CreateListFromArrayLike called on non-object или аналогичная

Изменения в современных версиях

С появлением стандарта ES6 (ES2015) потребность в использовании apply() для передачи массива аргументов уменьшилась. Оператор расширения (spread operator) ... позволяет достичь аналогичного результата с более лаконичным синтаксисом.

const numbers = [5, 10, 15];
function sum(a, b, c) {
    return a + b + c;
}
// Старый способ с apply
console.log(sum.apply(null, numbers));
// Новый способ с оператором расширения
console.log(sum(...numbers));
30
30

Несмотря на это, apply() остается частью стандарта и поддерживается во всех средах. Его использование для явной установки контекста по-прежнему актуально.

Расширенные примеры

Пример 1: Использование для вызова конструктора (устаревший способ, возможен до ES6).

function Person(name, age) {
    this.name = name;
    this.age = age;
}
const args = ['Игорь', 30];
const person = new (Person.bind.apply(Person, [null, ...args]))();
// Более современная альтернатива с оператором расширения:
const person2 = new Person(...args);
console.log(person2.name);
Игорь

Пример 2: Нахождение максимального значения в массиве.

const numbers = [4, 12, 7, 22, 5];
const max = Math.max.apply(null, numbers);
console.log(max);
// В ES6: Math.max(...numbers)
22

Пример 3: Композиция функций с использованием apply.

function compose(f, g) {
    return function() {
        return f.call(this, g.apply(this, arguments));
    };
}
function double(x) { return x * 2; }
function increment(x) { return x + 1; }
const doubleThenIncrement = compose(increment, double);
console.log(doubleThenIncrement(5));
11

Пример 4: Работа с массивоподобными объектами, например, arguments.

function logArgs() {
    // Преобразование arguments в массив для использования методов Array
    const argsArray = Array.prototype.slice.apply(arguments);
    argsArray.forEach(arg => console.log(arg));
}
logArgs('a', 'b', 'c');
a
b
c

JS apply function comments

En
Apply Calls a function with a given `this` value and arguments provided as an array