Тук ще разгледаме поведението на ключовата дума „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
Използването на функции със стрелки също ще помогне за смекчаване на тези проблеми. Нека да видим как се случва това в следващата статия за функциите на стрелките!