Czym jest słowo kluczowe `this` w języku JavaScript? Jak można efektywnie wykorzystać je w kodzie? To pytania, które często nurtują zarówno początkujących, jak i doświadczonych programistów JavaScript.
Jeżeli należysz do grona osób, które zastanawiają się nad istotą słowa kluczowego `this`, ten artykuł jest dla Ciebie. Wyjaśnimy, do czego odnosi się ono w różnych sytuacjach, oraz omówimy potencjalne problemy, które mogą pojawić się w kodzie.
`this` w zasięgu globalnym
W kontekście globalnym, czyli poza jakąkolwiek funkcją, `this` odnosi się do obiektu okna (window). Oznacza to, że jeśli użyjemy `this` w kodzie, który nie jest zawarty w definicji funkcji, to odwołujemy się do globalnego obiektu.
if(true) { console.log(this) }let i = 2 while(i < 10) { console.log(this) i++ }
Uruchomienie powyższego kodu spowoduje wyświetlenie obiektu okna w konsoli.
`this` wewnątrz funkcji (metod)
W przypadku użycia słowa kluczowego `this` wewnątrz funkcji, odnosi się ono do obiektu, z którym ta funkcja jest powiązana. Wyjątkiem jest sytuacja, gdy funkcja jest wywoływana samodzielnie – wówczas `this` wskazuje na obiekt okna. Przyjrzyjmy się kilku przykładom.
W poniższym przykładzie funkcja `sayName` jest umieszczona wewnątrz obiektu `me`, czyli pełni rolę metody. W takim przypadku `this` odnosi się do obiektu, który zawiera daną metodę.
function sayName() { return `My name is ${this.name}` }const me = { name: "Kingsley", sayName: sayName }
console.log(me.sayName())
W tym przypadku `this` reprezentuje obiekt `me`, co oznacza, że `this.name` wewnątrz metody `sayName` jest równoznaczne z `me.name`.
Inne podejście: `this` wskazuje na to, co znajduje się po lewej stronie wywołanej funkcji. To sprawia, że funkcja `sayName` może być wykorzystywana w różnych obiektach, a za każdym razem `this` będzie odnosić się do innego kontekstu.
Jak wspomniano, gdy funkcja jest wywoływana samodzielnie, `this` odnosi się do obiektu okna. Dzieje się tak, ponieważ funkcja samodzielna jest domyślnie powiązana z obiektem globalnym:
function talk() { return this }talk()
Wywołanie funkcji `talk()` jest tożsame z wywołaniem `window.talk()`. Wszystko, co znajduje się po lewej stronie wywołania funkcji, automatycznie staje się wartością `this`.
Warto dodać, że w trybie ścisłym JavaScript słowo kluczowe `this` w funkcji zachowuje się inaczej (zwraca wartość `undefined`). Należy o tym pamiętać podczas korzystania z bibliotek interfejsu użytkownika, takich jak React, które używają trybu ścisłego.
Użycie `this` z `Function.bind()`
Czasami nie możemy bezpośrednio dodać funkcji do obiektu jako metody (jak w poprzednim przykładzie).
Może obiekt pochodzi z zewnętrznej biblioteki i nie mamy możliwości jego modyfikacji. W takich przypadkach możemy wykorzystać metodę `Function.bind()` do wykonania funkcji w kontekście konkretnego obiektu.
W poniższym przykładzie, funkcja `sayName` nie jest metodą obiektu `me`, ale dzięki `bind()` możemy ją z nim powiązać:
function sayName() { return `My name is ${this.name}` }const me = { name: "Kingsley" }
const meTalk = sayName.bind(me)
meTalk()
Obiekt przekazany do `bind()` stanie się wartością `this` podczas wywołania tej funkcji.
Podsumowując, metoda `bind()` pozwala na powiązanie funkcji z nowym kontekstem (obiektem). Ten obiekt nadpisuje domyślną wartość `this` wewnątrz funkcji.
Użycie `this` z `Function.call()`
A co, jeśli nie chcemy tworzyć nowej funkcji, a jedynie wywołać istniejącą w określonym kontekście? W tym przypadku pomocna będzie metoda `call()`:
function sayName() { return `My name is ${this.name}` }const me = { name: "Kingsley" }
sayName.call(me)
Metoda `call()` natychmiast wykonuje funkcję, zamiast zwracać inną funkcję.
Jeśli funkcja przyjmuje parametry, można je przekazać za pomocą metody `call()`. W poniższym przykładzie, przekazujemy parametr `lang` do funkcji `sayName()`, co pozwala na zwracanie różnych komunikatów w zależności od języka:
function sayName(lang) { if (lang === "en") { return `My name is ${this.name}` } else if (lang === "it") { return `Io sono ${this.name}` } }const me = { name: "Kingsley" }
sayName.call(me, 'en') sayName.call(me, 'it')
Do funkcji możemy przekazać dowolną liczbę parametrów jako kolejne argumenty metody `call()`.
Metoda `apply()` działa bardzo podobnie do `call()`. Główna różnica polega na tym, że do `call()` argumenty przekazujemy oddzielnie, a do `apply()` przekazujemy je jako tablicę.
Podsumowując, metody `bind()`, `call()` i `apply()` pozwalają na wywołanie funkcji w kontekście innego obiektu, niezależnie od ich wzajemnego powiązania.
`this` w funkcjach konstruktora
Jeżeli funkcja zostanie wywołana z użyciem słowa kluczowego `new`, utworzy ona nowy obiekt `this` i go zwróci:
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
Powyższy kod utworzył trzy różne obiekty, używając tej samej funkcji. Słowo kluczowe `new` automatycznie tworzy powiązanie pomiędzy nowym obiektem a słowem kluczowym `this` wewnątrz funkcji.
`this` w funkcjach zwrotnych
Funkcje zwrotne (callback) różnią się od zwykłych funkcji. Są to funkcje przekazywane jako argument do innej funkcji, aby mogły zostać wywołane po zakończeniu wykonywania funkcji głównej.
Słowo kluczowe `this` w funkcjach zwrotnych odnosi się do zupełnie innego kontekstu:
function person(name){ this.name = name setTimeout(function() { console.log(this) }, 1000) }const me = new person("Kingsley")
Po jednej sekundzie od wywołania funkcji konstruktora `person` i utworzenia obiektu `me`, w konsoli zostanie wyświetlony obiekt okna jako wartość `this`. Oznacza to, że `this` w funkcji zwrotnej odnosi się do obiektu okna, a nie do utworzonego obiektu.
Można to naprawić na dwa sposoby. Pierwszy z nich polega na wykorzystaniu `bind()` do powiązania funkcji `person` z nowo utworzonym obiektem:
function person(name){ this.name = name setTimeout(function() { console.log(this) }.bind(this), 1000) }const me = new person("Kingsley")
W powyższym kodzie `this` w funkcji zwrotnej wskaże na to samo, co w funkcji konstruktora (obiekt `me`).
Drugim sposobem na rozwiązanie problemu z kontekstem `this` w funkcjach zwrotnych jest użycie funkcji strzałkowych.
`this` w funkcjach strzałkowych
Funkcje strzałkowe różnią się od zwykłych funkcji. Możemy zdefiniować funkcję zwrotną jako funkcję strzałkową. Dzięki funkcjom strzałkowym nie musimy już używać `bind()`, ponieważ automatycznie wiążą się one z kontekstem otaczającym, w tym przypadku z nowo utworzonym obiektem:
function person(name){ this.name = name setTimeout(() => { console.log(this) }, 1000) }const me = new person("Kingsley")
Dowiedz się więcej o JavaScript
Poznałeś już tajniki słowa kluczowego `this` i jego znaczenie w różnych kontekstach JavaScript. Jeśli dopiero zaczynasz przygodę z JavaScript, zrozumienie tych podstawowych aspektów będzie dla Ciebie bardzo korzystne.
newsblog.pl