Традиционно в JavaScript предоставляются объекты, обладающие собственными свойствами и методами. Например, object1
не может воспользоваться методами object2
и наоборот.
Однако есть способ обойти это ограничение.
Вы можете задействовать методы call()
, apply()
и bind()
для привязки функции к объекту и ее вызова, как если бы она принадлежала этому объекту.
Рассмотрим поочередно данные методы и приведем с ними примеры.
Метод Call() в JavaScript
Метод call()
вызывает функцию с заданным контекстом. Иначе говоря, вы привязываете функцию к объекту, как если бы она ему принадлежала.
Пример
Создадим объект obj
и функцию add()
для сложения одного числа с другим:
var obj = { num: 2 };function add(a){
return this.num + a;
}
На данном этапе с add()
возникает проблема. Она пытается вернуть this.num
вкупе с каким-то значением. Но в функции отсутствует свойство num
. Следовательно, вызвать this.num
не удается.
Но, как вы могли заметить, у объекта obj
есть свойство num
. А что если бы у нас была возможность вызвать функцию add()
для объекта, как если бы она ему принадлежала?
И такая возможность действительно есть. Для этого с помощью метода call()
мигом привязываем функцию add()
к объекту obj
:
add.call(obj, 3);
- Теперь функция
add()
получает свойthis
изobj
, к которому она привязана. - При вызове функции
add()
this.num
ссылается наnum
объектаobj
. - В результате вызов возвращает
5
, поскольку2 + 3 = 5
.
Call() с несколькими аргументами
Возможен вариант использования call()
с функциями, принимающими несколько аргументов.
Пример:
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
console.log(add.call(obj, 3, 5));
Вывод:
10
Метод Apply() в JavaScript
Метод apply()
аналогичен call()
. Отличие лишь в том, что call()
принимает список аргументов, а apply()
— массив.
Пример:
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
console.log(add.apply(obj, [3, 5]));
Вывод:
10
Метод Bind() в JavaScript
В предыдущих разделах мы выяснили суть методов call()
и apply()
: при вызове они моментально выполняют функцию и возвращают значение.
Принцип действия метода bind()
напоминает call()
и apply()
, но в отличие от них он возвращает функцию, выполнение которой может быть отложено.
Скорректируем предыдущий пример, применив bind()
:
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
const func = add.bind(obj, 3, 5);
func(); // Возвращает 10
Итак, вызов add.bind(obj, 3, 5)
возвращает функцию. В этом случае вы присваиваете ее константе func
и затем выполняете.
Здесь вызов func()
означает вызов функции add()
для объекта obj
с аргументами 3, 5
.
Думаю, принципы работы методов call()
, apply()
и bind()
понятны. Обобщим использование каждого из них с тем же самым объектом и привязанной к нему функцией, рассмотренными ранее.
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
const resultCall = add.call(obj, 3, 5);
const resultApply = add.apply(obj, [3, 5]);
const funcBind = add.bind(obj, 3, 5)
const resultBind = funcBind();
console.log(resultCall, resultApply, resultBind);
Вывод:
10 10 10
Применение Call() в JavaScript
Настало время посмотреть, как работает метод call()
в реальной жизни.
Call() для создания цепочек конструкторов объектов
Например, создаем объект Item
. Конструктор Item
определяется посредством name
и price
.
Теперь переходим к созданию объектов Car
и Fruit
, которые являются Items
. Но на этот раз их инициализацию проведем не вышеописанным способом, а воспользовавшись объектом Item
. Для этого понадобится метод call()
:
function Item(name, price) {
this.name = name;
this.price = price;
this.description = `${this.name}, ${this.price}€`;
}
function Car(name, price) {
Item.call(this, name, price);
// Здесь вы можете добавить другие поля, специфичные для Car
}
function Fruit(name, price) {
Item.call(this, name, price);
// Здесь вы можете добавить другие поля, специфичные для Fruit
}
const bmw = new Car("BMW", 120000);
const banana = new Fruit("Banana", 1);
Call() для вызова анонимной функции
Создадим анонимную функцию и посредством call()
вызовем ее для каждого объекта массива
Анонимная функция добавляет функцию displayInfo()
для каждого объекта массива, что позволяет вывести информацию о занимаемой позиции каждого человека в очереди:
const queue = [
{ name: 'Matt' },
{ name: 'Jack' }
];
for (let i = 0; i < queue.length; i++) {
(function(i) {
this.displayInfo = function() {
console.log(`Position ${i}: ${this.name}`);
}
this.displayInfo();
}).call(queue[i], i);
}
Вывод:
Position 0: Matt
Position 1: Jack
Call() для выполнения функции с объектом
С одним таким примером мы уже познакомились при определении call()
.
Речь идет о привязывании функции к объекту посредством метода call()
, благодаря чему вы ее вызываете, как если бы она принадлежала объекту:
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
console.log(add.call(obj, 3, 5));
Применение Apply() в JavaScript
Apply() для добавления одного массива к другому
Для добавления элементов в массив потребуется метод push()
.
При передаче массива в метод push()
он добавляет его целиком как один элемент — в итоге вы получаете массив в массиве. Здесь можно использовать concat()
, однако он создает новый массив.
Если нужно добавить массив целиком в уже существующий, задействуем apply()
.
Пример:
const numbers = [1, 2, 3];
const moreNumbers = [4, 5, 6];numbers.push.apply(numbers, moreNumbers);
console.log(numbers);
Вывод:
[1,2,3,4,5,6]
Apply() для создания цепочки конструкторов объектов
По аналогии с call()
можно создавать цепочки конструкторов объектов с помощью apply()
. На этот раз передаем массив с информацией в конструктор для инициализации объекта.
function Item(name, price) {
this.name = name;
this.price = price;
this.description = `${this.name}, ${this.price}€`;
}
function Car(details) {
Item.apply(this, details);
// Здесь вы можете добавить другие поля, специфичные для Car
}
function Fruit(details) {
Item.apply(this, details);
// Здесь вы можете добавить другие поля, специфичные для Fruit
}
const carDetails = ["BMW", 120000]
const bmw = new Car(carDetails);
const fruitDetails = ["Banana", 2]
const banana = new Fruit(fruitDetails);
Применение Bind() в JavaScript
Bind() для создания связанной функции
Посредством bind()
можно создать функцию, привязанную к объекту. При этом не имеет значения, где и как происходит ее вызов. Главное, что она вызывается вместе с объектом, с которым она связана.
Рассмотренный ранее пример иллюстрирует как раз этот случай.
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
const func = add.bind(obj, 3, 5);
func(); // Возвращает 10
Bind() для обеспечения работы SetTimeout
В этом фрагменте кода кроется проблема:
let person = {
name: 'John',
getName: function() {
console.log(this.name);
}
};
window.setTimeout(person.getName, 1000);
Вместо имени “John”
он выдает undefined
.
Выясним, в чем дело. Для этого перепишем последнюю строку по-другому:
let func = person.getName;
window.setTimeout(func, 1000);
Когда window
вызывает свой метод setTimeout()
, то объект this
является объектом window
. Следовательно, когда setTimeout()
вызывает func
, которая ссылается на person.getName()
, он не располагает информацией об имени person
. Для решения этой задачи привяжем функцию к объекту person
с помощью метода bind()
. В этом случае не имеет значения, где происходит вызов функции, — у нее всегда есть доступ к name
объекта person
.
let func = person.getName.bind(person);
setTimeout(func, 1000);
Вывод:
John
Данный прием работает по следующим причинам:
- Метод
person.getName
присваивается функцииfunc
, привязанной к к объектуperson
. - Теперь у
func
есть свойthis
, указывающий на объектperson
. При передаче связанной функции вsetTimeout()
func
по-прежнему знает, как получитьname
объектаperson
.
Заключение
В JavaScript для привязки функции к объекту можно задействовать методы call()
, apply()
и bind()
. В этом случае функция вызывается для объекта, как если бы она ему принадлежала.
- Методы
call()
иapply()
схожи в применении. Они оба сразу же выполняют связанную функцию для объекта. - В отличие от них метод
bind()
создает и возвращает связанную функцию, выполнение которой можно отложить.
Обобщим использование этих методов в следующем примере:
var obj = { num: 2 };
function add(a, b){
return this.num + a + b;
}
const resultCall = add.call(obj, 3, 5);
const resultApply = add.apply(obj, [3, 5]);
const funcBind = add.bind(obj, 3, 5)
const resultBind = funcBind();
console.log(resultCall, resultApply, resultBind);
Благодарю за внимание! Надеюсь, информация была полезной. Успехов в программировании!
Читайте также:
- 8 мощных пакетов NPM для любого веб-разработчика
- Интерфейсы с вкладками без JavaScript
- Темная сторона Javascript: избегайте данных трех функций
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Artturi Jalli: When to Use Bind(), Call(), and Apply() in JavaScript