Tento Älánek se zabývá pokroÄilým tématem, abychom lépe porozumÄli urÄitým okrajovým pÅÃpadům.
Toto téma nenà důležité. Mnoho zkuÅ¡ených vývojáÅů žije šťastnÄ i bez jeho znalosti. Älánek si pÅeÄtÄte, pokud chcete vÄdÄt, jak fungujà vÄci âpod kapotouâ.
Dynamicky vyhodnocované volánà metody může ztratit this.
NapÅÃklad:
let uživatel = {
jméno: "Jan",
ahoj() { alert(this.jméno); },
nashle() { alert("Nashle"); }
};
uživatel.ahoj(); // funguje
// nynà podle jména zavolejme uživatel.ahoj nebo uživatel.nashle
(uživatel.jméno == "Jan" ? uživatel.ahoj : uživatel.nashle)(); // Chyba!
Na poslednÃm Åádku je podmÃnÄný operátor, který vybere buÄ uživatel.ahoj, nebo uživatel.nashle. V tomto pÅÃpadÄ je výsledek uživatel.ahoj.
Pak je tato metoda okamžitÄ volána pomocà závorek (). Ale nefunguje to správnÄ!
Jak vidÃte, výsledkem volánà je chyba, protože hodnota "this" uvnitÅ volánà se stala undefined.
Tohle funguje (objekt teÄka metoda):
uživatel.ahoj();
Tohle ne (vyhodnocená metoda):
(uživatel.jméno == "Jan" ? uživatel.ahoj : uživatel.nashle)(); // Chyba!
ProÄ? Chceme-li porozumÄt, proÄ se to dÄje, podÃvejme se na zoubek tomu, jak funguje volánà obj.metoda().
VysvÄtlenà referenÄnÃho typu
Když se podÃváme pozornÄji, můžeme si v pÅÃkazu obj.metoda() vÅ¡imnout dvou operacÃ:
- Nejprve teÄka
'.'zÃská vlastnostobj.metoda. - Pak ji závorky
()spustÃ.
Jak se tedy informace o this pÅedá z prvnà Äásti do druhé?
UmÃstÃme-li tyto operace na samostatné Åádky, pak bude this zcela jistÄ ztraceno:
let uživatel = {
jméno: "Jan",
ahoj() { alert(this.jméno); }
}
// rozdÄlÃme zÃskánà a volánà metody na dva Åádky
let ahoj = uživatel.ahoj;
ahoj(); // Chyba, protože this je undefined
Zde ahoj = uživatel.ahoj vložà funkci do promÄnné a ta je pak na poslednÃm Åádku zcela samostatná, takže tam nenà žádné this.
Aby volánà uživatel.ahoj() fungovalo, JavaScript použÃvá trik â teÄka '.' nevracà funkci, ale hodnotu speciálnÃho referenÄnÃho typu.
ReferenÄnà typ je âspecifikaÄnà typâ. Nemůžeme jej explicitnÄ použÃvat, ale je použÃván vnitÅnÄ jazykem.
Hodnotou referenÄnÃho typu je tÅÃhodnotová kombinace (base, name, strict), kde:
base(základ) je objekt.name(název) je název vlastnosti.strict(striktnÃ) je true, pokud je použitouse strict.
Výsledkem pÅÃstupu k vlastnosti uživatel.ahoj nenà funkce, ale hodnota referenÄnÃho typu. Pro uživatel.ahoj ve striktnÃm režimu to je:
// hodnota referenÄnÃho typu
(uživatel, "ahoj", true)
Když se na referenÄnÃm typu zavolajà závorky (), obdržà úplnou informaci o objektu a jeho metodÄ a mohou tedy nastavit správné this (v tomto pÅÃpadÄ uživatel).
ReferenÄnà typ je speciálnà âzprostÅedkovatelskýâ internà typ, jehož úÄelem je pÅedat informaci z teÄky . volajÃcÃm závorkám ().
Jakákoli jiná operace, napÅ. pÅiÅazenà ahoj = uživatel.ahoj, celý referenÄnà typ zahodÃ, vezme hodnotu uživatel.ahoj (funkci) a pÅedá ji dál. Jakákoli dalšà operace tedy âztratÃâ this.
Výsledkem tedy je, že hodnota this se pÅedá správnÄ jen tehdy, je-li funkce volána pÅÃmo pomocà syntaxe teÄky obj.metoda() nebo hranatých závorek obj['metoda']() (obojà zde provádà totéž). Existujà různé způsoby, jak tento problém vyÅeÅ¡it, napÅ. funkce.bind().
ShrnutÃ
ReferenÄnà typ je internà jazykový typ.
NaÄtenà vlastnosti, napÅ. pomocà teÄky . v obj.metoda(), nevracà pÅesnÄ hodnotu vlastnosti, ale speciálnà hodnotu âreferenÄnÃho typuâ, v nÞ je uložena jak hodnota vlastnosti, tak objekt, z nÄhož byla pÅevzata.
To je proto, aby následné volánà metody () mohlo zÃskat objekt a nastavit jej jako this.
PÅi vÅ¡ech ostatnÃch operacÃch se z referenÄnÃho typu automaticky stává hodnota vlastnosti (v naÅ¡em pÅÃpadÄ funkce).
Celá tato mechanika je pÅed naÅ¡ima oÄima ukryta. Záležà na nà jen v krajnÃch pÅÃpadech, napÅÃklad když je metoda zÃskána z objektu dynamicky použitÃm výrazu.
KomentáÅe
<code>, pro nÄkolik Åádků je obalte znaÄkou<pre>, pro vÃce než 10 Åádků vložte odkaz na pÃskoviÅ¡tÄ (plnkr, jsbin, codepenâ¦)