Call: примеры (JAVASCRIPT)
call(thisArg, ...args): anyОсновные сведения о методе call
Метод call() является одним из способов явного указания контекста (this) для вызова функции в JavaScript. Этот метод принадлежит прототипу объекта Function, поэтому он доступен для любой функции.
Когда используется:
- Когда необходимо явно задать значение
thisвнутри функции. - Для заимствования методов у других объектов.
- Для вызова функций, которые могут быть определены в разных контекстах.
- В ситуациях, где требуется немедленный вызов функции с конкретным контекстом.
Аргументы:
- thisArg (обязательный): Значение, которое будет использоваться как
thisпри вызове функции. Если переданоnullилиundefined, в нестрогом режиме контекстом становится глобальный объект (например,window). В строгом режиме ('use strict') значение передается как есть. - arg1, arg2, ..., argN (необязательные): Аргументы, которые будут переданы вызываемой функции. Их количество не ограничено.
Возвращаемое значение:
Метод возвращает результат выполнения вызванной функции. Если функция не возвращает значение явно, будет возвращено undefined.
Простые примеры использования
Пример 1: Изменение контекста для метода объекта.
const person1 = { name: 'Анна' };
const person2 = { name: 'Иван' };
function greet(greeting) {
console.log(`${greeting}, ${this.name}!`);
}
greet.call(person1, 'Привет');
greet.call(person2, 'Здравствуй');Привет, Анна! Здравствуй, Иван!
Пример 2: Вызов функции без передачи конкретного объекта (нестрогий режим).
function showContext() {
console.log(this);
}
// В браузере
showContext.call(null); // Выведет объект Window (или global в Node.js)Window { ... }Пример 3: Использование в строгом режиме.
'use strict';
function showStrictContext() {
console.log(this);
}
showStrictContext.call(null); // null
showStrictContext.call(undefined); // undefinednull undefined
Похожие методы в JavaScript
Function.prototype.apply(): Очень похож на call, но принимает аргументы для вызываемой функции в виде массива (или массивоподобного объекта). Удобен, когда аргументы динамически формируются в коллекцию.
function sum(a, b, c) { return a + b + c; }
const numbers = [1, 2, 3];
console.log(sum.apply(null, numbers));6
Function.prototype.bind(): Создает новую функцию, которая при вызове имеет предустановленное значение this и, опционально, начальные аргументы. В отличие от call и apply, не вызывает функцию немедленно, а возвращает новую функцию для последующего вызова.
const boundGreet = greet.bind(person1, 'Привет');
boundGreet(); // Вызов позжеПривет, Анна!
Выбор метода:
Аналоги в других языках программирования
Python: Прямого аналога нет, так как self передается явно как первый параметр метода. Для вызова метода одного объекта с контекстом другого можно использовать types.MethodType или просто присвоить функцию как атрибут.
class Person:
def __init__(self, name):
self.name = name
def greet(self, greeting):
print(f'{greeting}, {self.name}!')
person1 = Person('Анна')
greet(person1, 'Привет') # Явная передача 'self'Привет, Анна!
PHP: Используют call_user_func() в сочетании с замыканиями (Closure::bind()) или call_user_func_array().
$greet = function($greeting) {
echo $greeting . ', ' . $this->name . '!';
};
$person1 = (object)['name' => 'Анна'];
$boundGreet = Closure::bind($greet, $person1);
$boundGreet('Привет');Привет, Анна!
C#: Прямого аналога для произвольной функции нет, но для делегатов можно использовать замыкания или явно передавать объект контекста как параметр.
Основное отличие JavaScript в том, что метод call является частью прототипа любой функции, обеспечивая единый и гибкий механизм управления контекстом.
Частые ошибки
Ошибка 1: Потеря контекста при передаче метода как коллбэка.
const obj = {
value: 10,
getValue: function() { console.log(this.value); }
};
setTimeout(obj.getValue, 100); // Контекст потеряется
// Решение:
setTimeout(obj.getValue.bind(obj), 100);
// Или с call, обернув в функцию:
setTimeout(() => obj.getValue.call(obj), 100);undefined // (или ошибка в strict mode) 10 // после исправления
Ошибка 2: Неверное значение thisArg в строгом режиме.
'use strict';
function func() { console.log(this); }
func.call(undefined); // Будет undefined, а не глобальный объектundefined
Ошибка 3: Использование call с примитивами. Примитивы оборачиваются в объекты.
function checkType() { console.log(typeof this); }
checkType.call(42); // 'object' (Number) в нестрогом режиме
checkType.call('text'); // 'object' (String)object object
История изменений
Метод Function.prototype.call был стандартизирован в ECMAScript 3 (1999) и с тех пор его поведение остается стабильным. В современных стандартах (ES5, ES6+) не было внесено значительных изменений в его работу. Единственное уточнение касается строгого режима ('use strict'), введенного в ES5, где значение thisArg не преобразуется в объект, если переданы null или undefined.
Расширенные примеры
Пример 1: Заимствование методов для массивоподобных объектов.
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
// Попытка использовать метод массива напрямую не сработает:
// arrayLike.forEach(...) // Ошибка
// Решение с call:
Array.prototype.forEach.call(arrayLike, item => console.log(item));a b
Пример 2: Цепочка вызовов конструкторов (наследование).
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price, category) {
Product.call(this, name, price); // Вызов родительского конструктора
this.category = category;
}
const bread = new Food('Хлеб', 30, 'Выпечка');
console.log(bread);Food { name: 'Хлеб', price: 30, category: 'Выпечка' }Пример 3: Оптимизация производительности с использованием call для вызова встроенных методов.
const arr = [5, 1, 9];
// Вместо Math.max.apply(null, arr):
const max = Math.max.call(null, ...arr); // С spread оператором
console.log(max);9
Пример 4: Динамический выбор контекста для функций высшего порядка.
function mapWithContext(arr, fn, context) {
const result = [];
for (let i = 0; i < arr.length; i++) {
result.push(fn.call(context, arr[i], i, arr));
}
return result;
}
const doubler = { factor: 2, multiply(x) { return x * this.factor; } };
console.log(mapWithContext([1, 2, 3], doubler.multiply, doubler));[2, 4, 6]
Пример 5: Эмуляция bind с использованием call.
function customBind(fn, context, ...boundArgs) {
return function(...args) {
return fn.call(context, ...boundArgs, ...args);
};
}
const boundFunc = customBind(greet, person1, 'Привет');
boundFunc();Привет, Анна!