Trochę więcej o this Spis treści
W poprzednich rozdziałach poznaliśmy tworzenie własnych obiektów oraz słowo kluczowe this, które "wskazywało na dany obiekt".
Poznanie działania this jest jedną z kluczowych spraw w Javascript, dlatego przypatrzmy mu się dokładniej.
Słowo this wskazuje na tak zwany execution context, czyli miejsce, kontekst, w którym wywoływany jest dany kawałek kodu.
Global context
Jeżeli nasz kod uruchamiany jest z najwyższego poziomu (czyli nie umieściliśmy go w żadnej funkcji), domyślnym kontekstem jest obiekt globalny, którym dla przeglądarek jest obiekt window (dla środowiska Node.js jest to obiekt module.exports (patrz rozdział o modułach))
Function context
Gdy odpalamy jakąś funkcję (poza funkcją strzałkową), w jej wnętrzu wartość this zależna jest od tego jak i gdzie ta funkcja jest wywoływana. Inaczej mówiąc następuje wiązanie this do jakiejś wartości.
Jeżeli funkcja nie jest metodą żadnego obiektu, wtedy w jej wnętrzu this będzie wskazywało na obiekt globalny:
console.log(this); //window
function test() {
console.log(this); //window
}
test();Wyjątkiem jest tutaj zastosowanie strict mode lub używanie modułów ES6 które automatycznie włączają ten tryb. Wówczas zarówno w przeglądarce jak i w Node.js wewnątrz odpalanej funkcji this będzie domyślnie wskazywać na undefined:
"use strict";
console.log(this); //window dla przeglądarki lub module.exports dla Node.js
function test() {
console.log(this); //undefined
}
test();Jeżeli jednak dana funkcja odpalana jest jako metoda danego obiektu, wtedy w jej wnętrzu this wskazuje zazwyczaj właśnie na ten obiekt:
Tak samo dzieje się w przypadku innych obiektów:
Powyższe zasady tyczą się każdego poziomu zagnieżdżenia:
Zmieniający się this
Wiedząc te wszystkie rzeczy, przejdźmy do kolejnego przykładu. Mamy więc obiekt, w który tworzymy metodę bindButton(), w której to pobieramy jakiś przycisk ze strony i podpinamy mu kliknięcie:
Po pierwsze czemu po kliknięciu na przycisk this z 13 linii wskazuje na btn?. Przeanalizuj poniższy kod:
Element/obiekt btn pobrany ze strony także ma metodę onclick, pod którą podstawiłem własną funkcję. Funkcja taka jest odpalana na kliknięcie (a to już robi wbudowany mechanizm). Skoro jest to metoda przycisku, to w jej wnętrzu this wskazuje właśnie na ten przycisk czyli w naszym przypadku obiekt btn.
Jak sprawić by po kliknięciu na przycisk this wskazywało na obiekt ob a nie btn?
Jest na to kilka sposobów.
Dodatkowa zmienna wskazująca na właściwe this
Pierwszym z nich jest stworzenie dodatkowej zmiennej, która będzie wskazywała na obiekt. Dzięki temu możemy się do niej odwoływać w funkcji, w której zmienione zostało this:
Nie jest to może najbezpieczniejsza metoda na świecie, ale w wielu przypadkach się sprawdza, a i jest całkiem logiczna w użyciu. To taki klasyk używany przez wiele skryptów.
Funkcja bind()
Drugim sposobem jest skorzystanie z funkcji bind(newThis, param1*, param2*...), która zwraca nam daną funkcję ze zmienionym w jej wnętrzu wiązaniem this.
Jako pierwszy parametr podajemy to co będzie podstawione pod this wewnątrz zwracanej funkcji, natomiast kolejne parametry to wartości, które przyjmuje modyfikowana funkcja - oczywiście jeżeli ich oczekuje.
Funkcja strzałkowa
W dzisiejszych czasach w podobnych sytuacjach najczęściej używana jest funkcja strzałkowa, która poza skróconym zapisem powoduje, że wewnątrz funkcji nie następuje wiązanie this, co oznacza, że this się nie zmienia. Osobiście lubię to nazywać "this jest brane z zewnątrz"
Jeżeli więc w powyższym kodzie podepniemy zdarzenie za pomocą funkcji strzałkowej, unikniemy problemu zmiany this:
Funkcja strzałkowa wraz z bind()
Funkcja strzałkowa jest bardzo fajnym sposobem na radzenie sobie z this, ale nie zawsze będzie wystarczającym rozwiązaniem.
Niestety muszę tu przejść do tematów, które jeszcze nie były przez nas omawiane, a dokładniej podpinania i odpinania zdarzeń.
Gdy podpinamy nasłuchiwanie zdarzenia do danego elementu, podajemy funkcję, która będzie odpalana w momencie wystąpienia takiego zdarzenia. Tak jak było to pokazane powyżej, domyślnie this w takiej funkcji wskazuje na dany element.
Jeżeli chcielibyśmy by this wskazywał na obiekt czy klasę w której takie podpięcie występuje, musimy - jak powyżej - użyć funkcji bind(), lub arrow function (metodę z dodatkową zmienną zostawmy na kiedy indziej):
I wszystko by było super gdybyśmy w przyszłości nie zapragnęli wyłączyć obsługi kliknięcia dla naszego przycisku. Jeżeli chcemy odpiąć nasłuchiwanie zdarzenia, zawsze musimy podawać referencję do funkcji którą właśnie podpinaliśmy (czyli podać nazwę wcześniej utworzonej funkcji).
W powyższym kodzie w żadnym z dwóch przypadków takiej referencji nie mamy, ponieważ zarówno pierwszy jak i drugi sposób tworzy nam zupełnie nowe funkcje.
Jak sobie poradzić w takim przypadku? Można zastosować podejście, stosowane w klasowych komponentach Reacta, które polega na wcześniejszym stworzeniu odpowiedniego wiązania:
Przy czym podobne wiązania najczęściej tworzone są od samego początku, czyli w konstruktorze klasy:
call() i apply()
Żeby ten kurs traktować jako kompletny, nie wypada nie wspomnieć o call() i apply(). W codziennym programowaniu raczej nie za często będziesz z nich korzystał (chyba, że będziesz używał kopiowanego kodu ze Stackoverflow), dlatego nie bierz sobie do serca, jeżeli nie będziesz ekspertem w użyciu tych metod.
Javascript udostępnia dla funkcji dwie dodatkowe metody call(this*, param1*, param2*...) i apply(this*, [param1, param2]*), które służą do wywoływania danej funkcji, z możliwością przekazania this w pierwszym parametrze.
Obie funkcje więc idealnie nadają się do "zapożyczania" metod z innych obiektów.
Jeżeli dana funkcja wymaga jakiś wartości, możemy je podać jako kolejne parametry metody obydwu metod. Różnicą jest tutaj to, że dla call() podajemy je po przecinku, natomiast dla apply() w formie tablicy:
Last updated