Як працює this в JavaScript

7 хв. читання

Новачкам (і не тільки ним) буває важко розібратися з ключовим словом this. Існує 5 правил, що допоможуть вам зрозуміти принцип роботи this та не плутатися в майбутньому. Звісно, ці правила не покривають всі випадки, але вони працюють в більшості ситуацій.

  1. Значення this залежить від контексту виконання. Контекст — це те, як і де функцію викликають.

  2. При кожному виклику функції 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 більше. Давайте підведемо короткий підсумок:

  1. Значення this зазвичай залежить від контексту виконання.

  2. В глобальній області видимості this вказує на глобальний об'єкт (window)

  3. Коли використовується ключове слово new, this вказує на об'єкт, що створюється.

  4. Ви можемо явно вказати значення this при виконанні функції за допомогою apply, call та bind..

  5. Стрілочні функції не змінюють this.

Помітили помилку? Повідомте автору, для цього достатньо виділити текст з помилкою та натиснути Ctrl+Enter
Codeguida 6.8K
Приєднався: 6 місяців тому
Коментарі (0)

    Ще немає коментарів

Щоб залишити коментар необхідно авторизуватися.

Вхід / Реєстрація