Привет, Хабр! Эту статью написал Тарас Голомозый, fullstack web-разработчик и преподаватель в школе программирования Elbrus Bootcamp. В своей практике он часто сталкивается с кейсами выпускников, которых на собеседовании просят рассказать о роли ключевого слова this в JavaScript. Простого определения про ссылку на контекст часто оказывается недостаточно, требуется более глубокое погружение в тему. В этой статье он на нескольких примерах разбирает, в каких ситуациях может пригодиться это ключевое слово и как используется 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. Если у вас появились вопросы или уточнения, пишите их в комментариях!
Комментарии (3)
iliazeus
23.11.2022 13:10+1Примеры вышли чересчур синтетическими. Из них не совсем понятно, в каких случаях нужны
call
/apply
/bind
в реальной жизни.Исходя из этих примеров, можно сказать, что
this
— это ссылка на объект, внутри которого находится это ключевое слово.Так думать опасно:
Welcome to Node.js v19.1.0. Type ".help" for more information. > var foo = { prop: 123, f: function () { return this.prop } } // this "внутри" foo undefined > var bar = { prop: 456 } undefined > bar.f = foo.f [Function: f] > bar.f() // но вернула bar.prop 456
Проще и правильнее всего думать о
this
как о том объекте, на котором метод вызвали. Несколько более глубокое объяснение уже есть на Хабре.
MaryRabinovich
По оформлению кода немного занудства: в первом примере с this вы передаёте в функцию лишние на этом этапе параметры. Вы их пока никак не используете внутри функции. Ну и дальше в примере с apply почему-то закомментированный код. И пример выводится без подсветки, серым.
domovoi89 Автор
Спасибо за уточнения! Все поправим, согласен