Яке значення має ключове слово this
у JavaScript? Як його можна ефективно застосовувати у ваших JavaScript програмах? Ці питання часто виникають як у новачків, так і у досвідчених розробників, коли справа доходить до розуміння ключового слова this
.
Якщо ви належите до тих, хто прагне розібратися з цим ключовим словом, ця стаття стане вашим путівником. Ми дослідимо, як this
поводиться в різних ситуаціях, та розглянемо типові помилки, яких слід уникати, щоб запобігти непорозумінням та багам у вашому коді.
this
у глобальній області видимості
В глобальному контексті, за межами будь-якої функції, this
повертає об’єкт window
. Глобальний контекст означає, що this
використовується поза межами будь-якої функції.
if(true) { console.log(this) }let i = 2 while(i < 10) { console.log(this) i++ }
Виконання наведеного вище коду покаже об’єкт window
.
this
всередині функцій (методів)
Коли this
використовується всередині функції, воно посилається на об’єкт, з яким пов’язана ця функція. Винятком є ситуація, коли this
використовується у звичайній, незв’язаній функції, тоді воно повертає об’єкт window
. Розглянемо декілька прикладів.
У наступному прикладі функція sayName
є частиною об’єкта me
(тобто це метод). В таких випадках this
вказує на об’єкт, що містить функцію.
function sayName() { return `Мене звати ${this.name}` }const me = { name: "Кінгслі", sayName: sayName }
console.log(me.sayName())
Тут this
є об’єктом me
, тому this.name
в методі sayName
еквівалентно me.name
.
Інший спосіб це зрозуміти: все, що знаходиться зліва від виклику функції, буде значенням this
. Це означає, що функцію sayName
можна використовувати в різних об’єктах, і в кожному випадку this
посилатиметься на інший контекст.
Як згадувалося раніше, this
повертає об’єкт window
, коли воно використовується всередині самостійної функції. Це відбувається тому, що за замовчуванням окрема функція пов’язана з об’єктом window
:
function talk() { return this }talk()
Виклик talk()
еквівалентний window.talk()
, і все, що знаходиться ліворуч від функції, автоматично стає значенням this
.
Варто зазначити, що поведінка ключового слова this
у функції змінюється у строгому режимі JavaScript (воно повертає undefined
). Це слід пам’ятати при використанні бібліотек, які застосовують строгий режим (наприклад, React).
Використання this
з Function.bind()
Іноді неможливо просто додати функцію до об’єкта як метод (як у попередньому розділі).
Об’єкт може бути вам не підвладний, або ви можете отримувати його з бібліотеки. Об’єкт є незмінним, і його не можна модифікувати. У таких ситуаціях можна викликати функцію окремо від об’єкта, використовуючи метод Function.bind()
.
У наведеному прикладі функція sayName
не є методом об’єкта me
, але ви все одно пов’язуєте її за допомогою bind()
:
function sayName() { return `Мене звати ${this.name}` }const me = { name: "Кінгслі" }
const meTalk = sayName.bind(me)
meTalk()
Будь-який об’єкт, переданий у bind()
, буде використовуватись як значення this
у виклику функції.
Таким чином, bind()
дозволяє використовувати будь-яку функцію, передаючи їй новий контекст (об’єкт). Цей об’єкт перезапише значення this
всередині функції.
Використання this
з Function.call()
А якщо потрібно не повертати нову функцію, а просто викликати наявну функцію, попередньо пов’язавши її з контекстом? Для цього існує метод call()
:
function sayName() { return `Мене звати ${this.name}` }const me = { name: "Кінгслі" }
sayName.call(me)
Метод call()
виконує функцію негайно, замість того, щоб повертати іншу функцію.
Якщо функції потрібні параметри, їх можна передати через метод call()
. У наступному прикладі передається параметр мови функції sayName()
, що дає можливість умовно повертати різні повідомлення:
function sayName(lang) { if (lang === "en") { return `Мене звати ${this.name}` } else if (lang === "it") { return `Я ${this.name}` } }const me = { name: "Кінгслі" }
sayName.call(me, 'en') sayName.call(me, 'it')
Як бачите, можна передати будь-який параметр у функцію як другий аргумент методу call()
. Можна передати скільки завгодно параметрів.
Метод apply()
дуже схожий на call()
та bind()
. Єдина відмінність полягає в тому, що множинні аргументи передаються через кому у call()
, тоді як в apply()
вони передаються у вигляді масиву.
Підсумовуючи, bind()
, call()
та apply()
дозволяють викликати функції з іншим об’єктом, не маючи між ними прямого зв’язку (функція не є методом об’єкта).
this
всередині функцій-конструкторів
Якщо викликати функцію з ключовим словом new
, створюється об’єкт this
, який потім повертається:
function person(name){ this.name = name }const me = new person("Кінгслі") const her = new person("Сара") const him = new person("Джейк")
me.name her.name him.name
У наведеному вище коді створено три різні об’єкти за допомогою однієї функції. Ключове слово new
автоматично створює зв’язок між створюваним об’єктом і ключовим словом this
у функції.
this
всередині функцій зворотного виклику
Функції зворотного виклику відрізняються від звичайних. Функції зворотного виклику передаються іншій функції як аргумент і викликаються після завершення виконання основної.
Ключове слово this
вказує на інший контекст, коли воно використовується у функціях зворотного виклику:
function person(name){ this.name = name setTimeout(function() { console.log(this) }, 1000) }const me = new person("Кінгслі")
Через секунду після виклику функції-конструктора person
і створення об’єкта me
, об’єкт window
буде виведений в консоль як значення this
. Тобто, при використанні у функції зворотного виклику, this
вказує на об’єкт window
, а не на “сконструйований” об’єкт.
Є два способи це виправити. Перший використовує bind()
для зв’язування функції person
з новоствореним об’єктом:
function person(name){ this.name = name setTimeout(function() { console.log(this) }.bind(this), 1000) }const me = new person("Кінгслі")
З цією модифікацією this
у функції зворотного виклику посилатиметься на те саме this
, що і у функції-конструкторі (об’єкт me
).
Другий спосіб розв’язання цієї проблеми у функціях зворотного виклику – використовувати стрілкові функції.
this
всередині стрілкових функцій
Стрілкові функції відрізняються від звичайних. Можна зробити функцію зворотного виклику стрілковою. Зі стрілковими функціями bind()
більше не потрібен, тому що вони автоматично пов’язуються з щойно створеним об’єктом:
function person(name){ this.name = name setTimeout(() => { console.log(this) }, 1000) }const me = new person("Кінгслі")
Дізнайтеся більше про JavaScript
Ви дізналися все про ключове слово this
та його значення в різних контекстах JavaScript. Якщо ви початківець у JavaScript, вам буде дуже корисно вивчити всі основи JavaScript та його роботу.