Новачкам (і не тільки ним) буває важко розібратися з ключовим словом this
. Існує 5 правил, що допоможуть вам зрозуміти принцип роботи this
та не плутатися в майбутньому. Звісно, ці правила не покривають всі випадки, але вони працюють в більшості ситуацій.
-
Значення
this
залежить від контексту виконання. Контекст — це те, як і де функцію викликають. -
При кожному виклику функції
this
може вказувати на різні об'єкти.
1. Глобальний об'єкт
Давайте відразу перейдемо до практики. Відкрийте консоль (Windows: Ctrl + Shift + J)(Mac: Cmd + Option + J) і наберіть наступне:
console.log(this);
Що ви отримали?
// Window {...}
Так, об'єкт window
. Це сталося тому що в глобальній області видимості this
вказує на глобальний об'єкт, а для браузера це window
.
Щоб краще зрозуміти чому так виходить, давайте трохи зануримося в теорію. Створіть нову змінну в консолі з вашим ім'ям.
var myName = 'Petro';
Ми можемо отримати його значення, викликавши:
myName
// 'Petro'
А чи знали ви, що всі змінні в глобальній області видимості прикріплені до об'єкта window
?
window.myName
// 'Brandon'
window.myName === myName
// true
Круто. Тепер ви знаєте трохи більше. А тепер давайте помістимо this
всередину функції. Згідно з правилом вище, значення this
залежить від способу виклику функції. Як думаєте, що поверне функція? Скопіюйте цей код в консоль браузера і перевірте свої здогадки:
function test() {
return this;
}
test()
this
все ще вказує на глобальний об'єкт. Це відбувається тому що this
знаходиться не всередині оголошеного об'єкту, тому і посилається на глобальний об'єкт. Це може бути трохи складно зрозуміти, тому просто продовжуйте читати, далі. Також слід зауважити, що якщо ви використовуєте суворий режим ("use strict";
), то в прикладі вище this буде вказувати на undefined
.
2. Оголошений об'єкт
Коли this
використовується всередині оголошеного об'єкту, він приймає значення найближчого предка. Подивіться на код, де я оголошую об'єкт person
і використовую this
всередині методу full
:
var person = {
first: 'Andrii',
last: 'Kovalcuk',
full: function() {
console.log(this.first + ' ' + this.last);
}
};
person.full();
// 'Andrii Kovalchuk'
Ви можете переконатися в тому, що this
вказує на потрібний об'єкт, замінивши тіло методу full
на console.log(this)
:
var person = {
first: 'Andrii',
last: 'Kovalcuk',
full: function() {
console.log(this);
}
};
person.full();
// Object {first: "Andrii", last: "Kovalchuk", full: function}
Перед тим, як рухатися далі, я хочу ще раз наголосити, що this
вказує на найближчого предка. Уявіть випадок коли в вас будуть вкладені об'єкти:
var person = {
first: 'Andrii',
last: 'Kovalchuk',
full: function() {
console.log(this.first + ' ' + this.last);
},
personTwo: {
first: 'Ivan',
last: 'Yarema',
full: function() {
console.log(this.first + ' ' + this.last);
}
}
};
Що станеться коли ми викличемо метод full
? Ось що:
person.full();
// 'Andrii Kovalchuk'
person.personTwo.full();
// 'Ivan Yarema'
3. Ключове слово new
Коли використовується ключове слово new
(конструктор), this
вказує на новий об'єкт, що створюється.
Розглянемо приклад:
function Car(make, model) {
this.make = make;
this.model = model;
};
Ви можете подумати, що this
буде вказувати на глобальний об'єкт, і це буде правдою. Допоки ми не додамо ключове слово new
! Тепер this
буде вказувати на новий об'єкт, в даному випадку myCar
.
var myCar = new Car('Ford', 'Escape');
console.log(myCar);
// Car {make: "Ford", model: "Escape"}
Щоб зрозуміти, чому так відбувається, вам потрібно знати як працює new
, але це — вже тема для окремої статті. А зараз ви повинні пам'ятати, що якщо перед викликом стоїть new
, то всередині this
вказує на новий об'єкт.
4. call
, bind
, apply
За допомогою цих функцій ми можемо явно вказати значення this
. Ці три функції схожі між собою, але тим не менш мають суттєві відмінності в роботі.
call
та apply
дуже схожі, вони обидва приймають значення this
та аргументи, і викликають функцію з цими даними. Різниця лиш в тому, що call
приймає аргументи окремо, а apply
— в масиві.
Не розумієте? Давайте розглянемо на прикладі. Ми намагаємось додати числа, але це не працює:
function add(c, d) {
console.log(this.a + this.b + c + d);
}
add(3,4);
// NaN
Функція повертає NaN (not a number), адже this.a
та this.b
не існує, а неможливо додати те, чого немає.
Давайте створимо новий об'єкт і використаємо call
та apply
:
function add(c, d) {
console.log(this.a + this.b + c + d);
}
var ten = {a: 1, b: 2};
add.call(ten, 3, 4);
// 10
add.apply(ten, [3,4]);
// 10
Коли ми використовуємо call
та apply
, this
прив'язується до значення першого аргументу і функція викликається з заданими параметрами.
А як щодо bind
? Параметри bind
ідентичні до call
, але bind
не викликає функцію, натомість він повертає іншу функцію, в якій this вже привязано. Це корисно коли ви не ще не знаєте з якими параметрами будуть викликати вашу функцію.
var small = {
a: 1,
go: function(b,c,d){
console.log(this.a+b+c+d);
}
}
var large = {
a: 100
}
Скопіюйте цей код в консоль, а потім виконайте:
small.go(2,3,4);
// 1+2+3+4 => 10
Поки що нічого нового. А якщо ви хочемо викликати функцію, використавши large.a
? Ви можемо використати call
/apply
:
small.go.call(large,2,3,4);
// 100+2+3+4 => 109
А якщо ми не знаємо всі три параметри? Ми використовуємо bind.
var bindTest = small.go.bind(large,2);
Якщо ми виведемо нашу змінну, то побачимо, що це функція:
console.log(bindTest);
// function (b,c,d){console.log(this.a+b+c+d);}
Як ви пам'ятаєте, bind
створює контекст виконання. Ми вже задали значення this
та наш перший аргумент. Пізніше, коли ви дізналися всі параметри, ви можете викликати функцію, передавши лише два аргументи:
bindTest(3,4);
// 100+2+3+4 => 109
Для вашої зручності ось весь код одним блоком. Експерементуйте!
var small = {
a: 1,
go: function(b,c,d){
console.log(this.a+b+c+d);
}
}
var large = {
a: 100
}
small.go(2,3,4);
// 1+2+3+4 => 10
var bindTest = small.go.bind(large,2);
console.log(bindTest);
// function (b,c,d){console.log(this.a+b+c+d);}
bindTest(3,4);
// 100+2+3+4 => 109
5. Стрілочні функції
Що таке стрілочна функція і як вона взаємодіє з this
можна почитати в іншій нашій статті тут. Але якщо коротко, то стрілочні функції не змінюють this
, вони беруть його з контексту.
Підсумки
Тепер ви знаєте про JavaScript більше. Давайте підведемо короткий підсумок:
-
Значення
this
зазвичай залежить від контексту виконання. -
В глобальній області видимості
this
вказує на глобальний об'єкт (window
) -
Коли використовується ключове слово
new
,this
вказує на об'єкт, що створюється. -
Ви можемо явно вказати значення
this
при виконанні функції за допомогоюapply
,call
таbind.
. -
Стрілочні функції не змінюють
this
.
Ще немає коментарів