Тук ще разгледаме поведението на ключовата дума „this“ в различни контексти на javascript.

Както е споменато в описанието на темата, ключовата дума „тази“ се отнася до различни обекти въз основа на контекста и начина, по който се случва извикването.

1. традиционни функции (функциите започват с ключова дума function):

function myFunction() {
  console.log(this === global)
};
myFunction();
// prints true

Тъй като функцията се извиква в глобален обхват, тук „това“ се отнася до глобалния обект (обект на прозорец в средата на браузъра).

2. традиционна функция с „нова“ ключова дума

function myFunction() {
  console.log(this)
}
const test = new myFunction()
test;
// prints: myFunction {}

С използването на ключовата дума “new” ще извика конструктора на myFunction и ще създаде нов екземпляр на myFunction. Вътре в този нов екземпляр ключовата дума „this“ се отнася до самия обект.

3. традиционна функция вътре в обекта

метод 01:

const obj = {
  myFunction() {
    console.log(this === global);
  }
};
const test = obj.myFunction;
test();
// prints: true

метод 02:

const obj = {
  myFunction() {
    console.log(this === global);
  }
};
obj.myFunction();
// prints: false

В метод номер 01 извличаме функцията от обекта и извикваме функцията на глобално ниво. Тогава ключовата дума „this“ се отнася до глобалния обект.

В метод номер 02 извикваме функцията, когато тя остава вътре в обекта. Тогава ключовата дума „това“ се отнася до самия обект.

4. вложени функции

const obj = {
  myFunction() {
    console.log(this)
  },
nestedFunction() {
    function innerFunction() {
      console.log(this);
    }
    return innerFunction()
  }
  
}
obj.nestedFunction();

prints: global object

В този пример извикваме „nestedFunction” вътре в обекта, но „this” все още се отнася до глобалния обект. Защо?????

Въпреки че извикахме вложената функция в обхвата на обекта, извикването на „innerFunction“ става директно. Така че ключовата дума „this“ вътре във „innerFunction“ се отнася до глобалния обект.

Важно: Как се извиква функцията има значение!!!!!!!!!!.

Често срещани злоупотреби с „това“

номер 01:

function Bottle() {
  return this;
}
const bottle1 = Bottle();
const bottle2 = Bottle();
bottle1.waterLevel = 100;
bottle2.waterLevel = 200;
console.log(bottle1.waterLevel);
console.log(bottle2.waterLevel);
prints : 200
         200

Обектите bottle1 и bottle2 се отнасят за един и същ глобален обект и настройването на атрибута waterLevel на bottle1 ще добави нов запис към глобалния обект. Тази стойност ще бъде презаписана, докато задавате нивото на водата за бутилка2.

Това може да се коригира с помощта на ключовата дума „new“:

function Bottle() {
  return this;
}
const bottle1 = new Bottle();
const bottle2 = new Bottle();
bottle1.waterLevel = 100;
bottle2.waterLevel = 200;
console.log(bottle1.waterLevel);
console.log(bottle2.waterLevel);
prints: 100
        200

Ключовата дума „ново“ ще създаде два отделни екземпляра на обект тип бутилка. И „това“ ще се отнася до самия екземпляр.

номер 02:

const bottle = {
  waterLevel: 100,
  refillWater() {
    setTimeout(function (){
      console.log("refilled, new amount is : ", this.waterLevel+100)
    }, 1000)
  }
}
bottle.refillWater();
prints: refilled, new amount is :  NaN

Когато използваме вградени функции като setTimeout, това е често срещана грешка, която много от нас правят. Функцията за обратно извикване, която преминава за зададеното време за изчакване, се извиква директно и ключовата дума „this“ ще се отнася до глобалния обект. Не сме задали атрибут, наречен waterLevel в глобалния обект. Така че резултатът ще бъде NaN.

Можем да разрешим това с помощта на малък хак;)

const bottle = {
  waterLevel: 100,
  refillWater() {
    _this = this;
    setTimeout(function (){
      console.log("refilled, new amount is : ", _this.waterLevel +100);
    }, 1000)
  }
}
bottle.refillWater();
prints: refilled, new amount is :  200

Използването на функции със стрелки също ще помогне за смекчаване на тези проблеми. Нека да видим как се случва това в следващата статия за функциите на стрелките!