Správné pochopení „this“^mdn bývá pro vývojáře v javascriptu největší výzvou. V objektově orientovaném programování odkazuje na aktuální instanci třídy nebo objektu, což může vést k nejasnostem a chybám, pokud není správně použito.
Ve funkcích (mimo arrow funkce) se hodnota this
mění v závislosti na tom, jak je funkce volána, tedy this
odkazuje na exekuční kontext funkce.
Hodnota this
pak odkazuje pokaždé na něco jiného v závislosti na tom, kde se v programu nachází a v jakém kontextu se vyskytuje.
Jiné this
očekáváme ve funkcích (způsobem jak se funkce volá), třídách (jaký objekt je v daný moment používán) nebo globálním kontextu.
Tato konstrukce může to být na první pohled znít komplikovaně a asi lépe než se popisuje, je lepší chování this
demonstrovat na příkladech.
Proto v tomto příspěvku shrnu na příkladech několik různých kontextů a ukážu, co by this
v každém případě představovalo.
Globální kontext
Co se stane, když se na this
odkážete v globálním kontextu (tj. nikoli uvnitř nějaké funkce)?
V globálním kontextu, odkazuje na celý globální objekt (v případě prohlížeče je to objekt window).
console.log(this === window); // true
console.log(this === globalThis); // true
Toto můžete jednoduše otestovat v prohlížeči v Dev tools zadáním tohoto řádku do konzole.
Způsoby voláni funkce
Ve většině případů je tato hodnota určena způsobem volání funkce (runtime binding). Nelze ji nastavit přiřazením během provádění a při každém volání funkce může být jiná.
Můžeme si this
ve funkci představit jako skrytý argument.
Kontext funkce
Pokud jsou funkce prováděny v globálním kontextu, tedy není volána uvnitř žádné jiné funkce nebo objektu, může být hodnotou tohoto parametru objekt window/globalThis. Zdůrazňuji slovo může. Protože se to liší od režimu ve kterém je JS spouštěn. Uvažujme následující příklad:
var myFunciton = function(){
console.log(this);
console.log(this === window); // ve striktním režimu vrátí true
}
Ve striktním režimu bude hodnota this
v globálním kontextu nedefinovaná.
Navíc myFunction()
je pak equivalentní volání window.myFuntion()
.
Volání metody objektu
Ve volání metod je this
roven hodnotě objektu, který funkci volá.
const obj = {
name: 'Pro vývojáře',
printThis: function() {
return this === obj; // true
},
getName: function() {
return this.name;
}
};
console.log(obj.getName()); // 'Pro vývojáře'
console.log(obj.printThis()); // true
Objekt "this" odkazuje na "obj", protože funkce "getName" je volána jako metoda "obj".
Nezáleží nikoliv na tom, kde je funkce definována. Ukázka tzv. runtime bindingu.
const obj2 = {
name: 'Můj objekt',
getName: obj.getName
};
console.log(obj.getName()); // Výstup: 'Pro vývojáře'
console.log(obj2.getName()); // Výstup: 'Můj objekt'
Ve výše uvedeném příkladu jsou obě volání funkce getName
identické, ale v obou případech má this
odlišnou hodnotu.
V prvním případě odkazuje this
na obj
, zatímco v druhém případě odkazuje this na obj2
.
Volání konstruktoru
Pokud je funkce použita jako konstruktor (s klíčovým slovem new), je její hodnota this vázána na konstruovaný nový objekt. Hodnota této funkce se bude rovnat novému vytvořenému objektu.
Ve výrazu Immediately Invoked Function (IIFE)
V IIFE je hodnota tohoto parametru vždy rovna objektu window
. Podívejme se na příklad:
// IIFE mimo jakoukoli funkci
(function() {
console.log(this); // Output: Window object
})()
// IIFE inside an object function
var obj = {};
var someFunc = function() {
console.log("Functions this");
console.log(this === obj);
console.log('++++++++++++++++++++++++++');
// IIFE
(function() {
console.log("IIFE this");
console.log(this); // Output: Window object
console.log("IIFE");
})()
};
obj.func = someFunc;
obj.func();
Par poznámek pod čarou
Jak použít arrow funkci s klíčovým slovem "this"?
Arrow funkce nemají vlastní this
, ale jsou lexikálně bindované na funkci, ve které byla definována.
Pomocí reflexe můžete this ve funkci změnit, ukázky jsou v samostatném článku.