Utracona referencja this w JavaScript
Załóżmy, że mamy funkcję wewnątrz funkcji. Nazwijmy
funkcję zewnętrzną parent, a
wewnętrzną - child:
function parent() {
function child() {
}
}
Z poprzednich lekcji wiesz, że jeśli zdefiniujesz jakąś zmienną w funkcji zewnętrznej - będzie ona dostępna w funkcji wewnętrznej:
function parent() {
let str = 'abcde';
function child() {
console.log(str); // wypisze 'abcde'
}
child(); // wywołujemy funkcję wewnętrzną
}
parent(); // wywołujemy funkcję zewnętrzną
Istnieje jednak niuans: funkcja wewnętrzna ma
dostęp do wszystkich zmiennych funkcji zewnętrznej, ale nie
ma dostępu do this. To znaczy: jeśli
funkcja zewnętrzna jest powiązana z jakimś elementem DOM,
to this w niej będzie wskazywać
na ten element, ale this funkcji wewnętrznej
- nie będzie!
Na co w takim razie będzie wskazywać this
funkcji wewnętrznej? Odpowiedź: będzie równy
undefined (w trybie ścisłym), ponieważ
funkcja nie jest z niczym powiązana.
Sprawdźmy to w praktyce. Załóżmy, że mamy daną pole input:
<input id="elem" value="text">
Powiążmy z tym inputem funkcję parent,
która będzie wywoływana po utracie fokusu przez input:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
// Wywoła się po utracie fokusu:
function parent() {
// tutaj będzie jakiś kod
function child() {
// tutaj będzie jakiś kod
}
child(); // wywołujemy funkcję potomną
}
Wypiszmy zawartość this do
konsoli w dwóch miejscach: wewnątrz funkcji parent
i wewnątrz funkcji child:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this); // wypisze referencję do naszego inputa
function child() {
console.log(this); // wypisze undefined
}
child();
}
Uruchom ten kod, spraw by input stracił fokus
i spójrz do konsoli - zobaczysz, że
pierwszy console.log wypisze do konsoli
referencję do naszego inputa, a drugi - po prostu undefined.
Taka sytuacja, gdy this w nieoczekiwany
dla nas sposób wskazuje nie na to, czego
potrzebujemy, nazywa się utratą kontekstu.
Załóżmy teraz, że w jednej i w drugiej funkcji
będziemy wypisywać value inputa. Określ,
co zostanie wypisane w linijkach kodu oznaczonych
komentarzami:
"use strict";
let elem = document.querySelector('#elem');
elem.addEventListener('blur', parent);
function parent() {
console.log(this.value); // co wypisze?
function child() {
console.log(this.value); // co wypisze?
}
child();
}