Co je this?

AndreaAndrea

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.