Pochopení JavaScriptového klíčového slova „toto“.

Co přesně v JavaScriptu znamená klíčové slovo this? Jak jej můžeme efektivně využít při programování? To jsou otázky, které si často kladou začátečníci, a dokonce i zkušení vývojáři. Klíčové slovo this může být pro mnohé matoucí.

Pokud i vy patříte k těm, které toto téma zajímá, pak je tento článek určen přímo vám. Společně prozkoumáme jeho význam v různých kontextech a upozorníme na potenciální problémy, abyste se vyhnuli nejasnostem a chybám v kódu.

this v globálním kontextu

Pokud se nacházíme v globálním kontextu, mimo jakoukoliv funkci, this odkazuje na objekt window. Globální kontext znamená, že klíčové slovo this nepoužíváte uvnitř žádné funkce.

 if(true) {
  console.log(this) 
}
let i = 2
while(i < 10) {
  console.log(this)
  i++
}

Při spuštění výše uvedeného kódu získáte jako výstup objekt window.

this uvnitř funkcí (metod)

V případě použití this uvnitř funkcí, odkazuje na objekt, ke kterému je daná funkce vázána. Jedinou výjimkou je situace, kdy this použijete v samostatné funkci. V takovém případě se this opět stává odkazem na objekt window. Projděme si několik příkladů.

V následujícím kódu je funkce sayName definována uvnitř objektu me (tj. jedná se o metodu). V takových situacích this odkazuje na objekt, který danou funkci obsahuje.

 
function sayName() {
  return `Moje jméno je ${this.name}`
}
const me = {
  name: "Kingsley",
  sayName: sayName
}

console.log(me.sayName()) 

Zde this reprezentuje objekt me, a proto this.name uvnitř metody sayName je ekvivalentní me.name.

Další způsob, jak si to představit, je, že cokoliv se nachází nalevo od volané funkce, se stává hodnotou this. To znamená, že funkci sayName můžeme znovu použít i v jiných objektech, a this bude pokaždé odkazovat na jiný kontext.

Jak už bylo zmíněno, v případě samostatné funkce, this vrací objekt window. Je to proto, že samostatná funkce je standardně asociována s objektem window:

 function talk() {
  return this
}
talk()

Volání talk() je ekvivalentní volání window.talk(), a tak se cokoliv nalevo od funkce automaticky stává this.

Je také důležité zmínit, že chování this ve funkcích se liší v přísném režimu JavaScriptu (vrací undefined). To je důležitý fakt, pokud používáte například knihovny uživatelského rozhraní, které přísný režim používají (např. React).

Použití this s funkcí Function.bind()

Někdy nemusíte mít možnost jen tak přidat funkci k objektu jako metodu (jak bylo ukázáno dříve).

Možná daný objekt není váš, a čerpáte ho z knihovny. Nebo je objekt neměnný a nemůžete ho přímo upravovat. V takových případech můžeme s výhodou využít metodu Function.bind().

V následujícím příkladu funkce sayName není metodou objektu me, ale přesto ji svážeme pomocí bind():

 function sayName() {
  return `Moje jméno je ${this.name}`
}
const me = {
  name: "Kingsley"
}

const meTalk = sayName.bind(me)

meTalk()

Objekt, který předáme metodě bind(), se použije jako hodnota this pro volání této funkce.

Zjednodušeně, můžeme použít bind() na jakoukoli funkci a předat nový kontext (objekt), který přepíše význam this uvnitř dané funkce.

Použití this s funkcí Function.call()

Co když nechcete vracet novou funkci, ale raději ji chcete rovnou zavolat po navázání na daný kontext? Pak použijeme metodu call():

 function sayName() {
  return `Moje jméno je ${this.name}`
}
const me = {
  name: "Kingsley"
}

sayName.call(me)

Metoda call() okamžitě provede funkci namísto vracení jiné funkce.

Pokud funkce vyžaduje parametry, můžeme je předat pomocí call(). Následující příklad předává jazyk do funkce sayName(), abychom mohli podmíněně vracet různé zprávy:

 function sayName(lang) {
  if (lang === "en") {
    return `Moje jméno je ${this.name}`
  } else if (lang === "it") {
    return `Io sono ${this.name}`
  }
}
const me = {
  name: "Kingsley"
}

sayName.call(me, 'en')
sayName.call(me, 'it')

Jak vidíte, můžeme funkci předat libovolný parametr jako další argument metody call(). Počet parametrů není omezen.

Metoda apply() je velmi podobná metodám call() a bind(). Hlavním rozdílem je, že zatímco v call() předáváme parametry oddělené čárkami, v apply() je předáváme uvnitř pole.

Stručně řečeno, bind(), call() a apply() umožňují volat funkce s naprosto jiným objektem, i když mezi nimi není žádný vztah (tj. funkce není metodou na objektu).

this uvnitř konstruktorů

Při volání funkce s klíčovým slovem new, se vytvoří nový objekt this, a ten se následně vrátí:

 function person(name){
  this.name = name
}
const me = new person("Kingsley")
const her = new person("Sarah")
const him = new person("Jake")

me.name
her.name
him.name

V kódu výše jsme vytvořili tři různé objekty ze stejné funkce. Klíčové slovo new automaticky vytvoří vazbu mezi vytvářeným objektem a this uvnitř funkce.

this uvnitř zpětných volání

Zpětná volání se chovají trochu jinak než klasické funkce. Zpětné volání je funkce, kterou předáváme jiné funkci jako argument a která se má provést po dokončení hlavní funkce.

V případě zpětných volání se this chová odlišně:

 function person(name){
  this.name = name
  setTimeout(function() {
    console.log(this)
  }, 1000)
}
const me = new person("Kingsley")

Po jedné sekundě od volání konstruktoru person a vytvoření nového objektu me, se jako hodnota this zaloguje objekt window. Tedy v tomto případě this odkazuje na objekt window, a ne na „vytvořený“ objekt.

Existují dva způsoby, jak to vyřešit. První metoda využívá bind() k navázání funkce person na nově vytvořený objekt:

 function person(name){
  this.name = name
  setTimeout(function() {
    console.log(this)
  }.bind(this), 1000)
}
const me = new person("Kingsley")

Po této úpravě, this ve zpětném volání bude odkazovat na stejný objekt jako uvnitř konstruktoru (objekt me).

Druhým způsobem, jak vyřešit problém s this ve zpětných voláních, je použití arrow funkcí.

this uvnitř arrow funkcí

Arrow funkce (funkce šipky) se liší od klasických funkcí. Můžeme tedy zpětné volání změnit na arrow funkci. S arrow funkcemi již bind() nepotřebujeme, protože se automaticky váží na nově vytvořený objekt:

 function person(name){
  this.name = name
  setTimeout(() => {
    console.log(this)
  }, 1000)
}
const me = new person("Kingsley")

Další informace o JavaScriptu

V tomto článku jste se dozvěděli o klíčovém slově this a o jeho významu v různých kontextech JavaScriptu. Pokud s JavaScriptem začínáte, je důležité naučit se všechny jeho základy a porozumět tomu, jak funguje. Věřím, že tyto informace vám pomohou lépe pracovat s JavaScriptem.