Как работают this, call, apply и bind в JavaScript: разбираемся на примерах

Как работают this, call, apply и bind в JavaScript: разбираемся на примерах

На собеседовании веб-разработчика могут спросить, какую роль ключевое слово this играет в JavaScript. Простого ответа про ссылку на контекст может быть недостаточно: в этой концепции есть много тонкостей. Fullstack web-разработчик и преподаватель в школе программирования Elbrus Bootcamp Тарас Голомозый на простом примере разобирает, в каких ситуациях может пригодиться это ключевое слово, а где используется call, apply и bind.

В общем смысле this — это ссылка на определенный контекст внутри объекта. Рассмотрим, что это означает, на примере.

Создадим объект car с набором свойств: моделью и годом выпуска автомобиля.

const car = {
  model: 'Toyota',
  year: 2007,
    }

Для того, чтобы обратиться к объекту извне, достаточно выбрать имя переменной и через точку выбрать любое свойство: например, model.

console.log (car.model)

В консоли мы увидим модель автомобиля: Toyota.

Обратиться к объекту изнутри сложнее: находясь внутри фигурных скобок, мы не знаем, куда будет записан объект и будет ли записан вообще. Попробуем сделать это, создав внутри объекта функцию showModel. Ее единственная задача — показывать модель автомобиля:

const car = {
  model: 'Toyota',
  year: 2007,
  showModel: function(model, year){
  console.log(this.model);
  }
};

Чтобы из этой функции получить доступ к model, пишем this.model. Благодаря ключевому слову this можно получить доступ к любому свойству объекта, находясь внутри него.

Теперь из объекта car можно вызвать showModel — метод покажет модель автомобиля, Toyota.

Допустим, у нас есть еще один автомобиль. Создадим новый объект и назовем его anotherCar. У этого объекта будут те же свойства: model и year.

const anotherCar = {
  model: 'Benz',
  year: 1998
 showModel: function(model, year){
  console.log(this.model);
  }
};

Если скопировать функцию showModel с this внутрь нового объекта, то при вызове anotherCar.showModel, то в консоли мы увидим модель той машины, внутри которой вызывается этот метод. В данном случае — Benz.

Исходя из этих примеров, можно сказать, что this — это ссылка на объект, внутри которого находится это ключевое слово.

Важно отметить, что функции бывают обычными (как в этом примере) и стрелочными. Если в этом примере заменить функцию на стрелочную, в консоли мы увидим undefined. Дело в том, что стрелочные функции не имеют своего this.

Call, apply и bind

Что делать, если у второго автомобиля нет метода, который показывает его модель? Можем ли мы использовать функцию с вызовом модели первого автомобиля? Да, для этого в JavaScript есть специальные ключевые слова: call, apply и bind.

Начнем с call. Вызываем из первой машины метод car.showModel, используя call. В качестве аргумента ключевого слова указываем название объекта, в который записан второй автомобиль, anotherCar. В консоли мы увидим Benz.

То же самое можно сделать с помощью метода apply, просто меняя ключевое слово: car.showModel.apply(anotherCar);. Результат будет таким же: в консоли мы увидим Benz.

Возникает вопрос — чем call отличается от apply? Разница между ними в формате передачи параметров. Рассмотрим пример: функция showModel, кроме вывода модели автомобиля, может принимать еще какие-то параметры: например, цвет автомобиля и тип двигателя.

const car = {
  model: 'Toyota',
  year: 2007,
  showModel: function(color, engine){
    console.log(this.model, color, engine);
  }
};

Используя apply, новые параметры можно передать в виде массива: например, автомобиль будет красным и с бензиновым двигателем:

// car.showModel.apply(anotherCar, ['red', 'diesel']);

В консоли мы увидим, что это красный дизельный Benz.

Call позволяет передать те же параметры не в виде массива, а простым перечислением:

// car.showModel.call(anotherCar, 'green', 'gas').

Третий метод, bind, позволяет создать новую функцию и записать ее в переменную. Выглядеть это будет так:

const modelShower = car.showModel.bind(anotherCar);
modelShower('black', 'diesel');

Функция modelShower вызывает методshowModel, а bind привязывает к нему контекст другого автомобиля — в нашем случае это anotherCar.Таким образом, в переменной modelShower появилась функция, способная показывать контекст anotherCar так, будто она написана внутри самого anotherCar.

Передадим в функцию цвет и параметры двигателя:

modelShower('black', 'diesel');

В выводе мы, как и ожидалось, получим черный дизельный Benz.

Заключение

Рады, если теперь вам удалось разобраться, что такое this в JavaScript, в чем разница между call и apply и для чего нужен bind. Если у вас появились вопросы или уточнения, пишите их в комментариях!