Ztráta kontextu v JavaScriptu
Předpokládejme, že máme funkci ve funkci. Pojmenujme
vnější funkci parent a
vnitřní - child:
function parent() {
function child() {
}
}
Z předchozích lekcí víte, že pokud nastavíte nějakou proměnnou ve vnější funkci - bude dostupná ve vnitřní:
function parent() {
let str = 'abcde';
function child() {
console.log(str); // vypíše 'abcde'
}
child(); // voláme vnitřní funkci
}
parent(); // voláme vnější funkci
Existuje však nuance: vnitřní funkce má
přístup ke všem proměnným vnější, ale
nemá přístup k this. To znamená: pokud
je vnější funkce navázána na nějaký DOM
prvek, pak this v ní bude ukazovat
na tento prvek, ale this vnitřní
funkce - nebude!
Na co tedy bude this
vnitřní funkce ukazovat? Odpověď: bude roven
undefined (v striktním režimu), protože
funkce není na nic navázána.
Ověřme si to v praxi. Předpokládejme, že máme dán input:
<input id="elem" value="text">
Navážeme na tento input funkci parent,
která se bude volat při ztrátě focusu inputem:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
// Zavolá se při ztrátě focusu:
function parent() {
// tady bude nějaký kód
function child() {
// tady bude nějaký kód
}
child(); // voláme dceřinou funkci
}
Vypišme obsah this do
konsole na dvou místech: uvnitř funkce parent
a uvnitř funkce child:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this); // vypíše odkaz na náš input
function child() {
console.log(this); // vypíše undefined
}
child();
}
Spusťte tento kód, ztratťe focus inputu
a podívejte se do konsole - uvidíte, že
první console.log vypíše do konsole
odkaz na náš input, a druhý - prostě undefined.
Takovou situaci, kdy this nečekaným
způsobem neukazuje na to, co potřebujeme,
se nazývá ztráta kontextu.
Předpokládejme nyní, že v jedné i ve druhé funkci
budeme vypisovat value inputu. Určete,
co se vypíše na řádcích kódu, označených
komentáři:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this.value); // co vypíše?
function child() {
console.log(this.value); // co vypíše?
}
child();
}