Dynamiczna natura kontekstu
W odróżnieniu od innych popularnych języków programowania kontekst funkcji this w JavaScript jest dynamiczny i zależny od sposobu w jaki funkcja została wywołana. Oznacza to, że jest on ustalany dopiero w momencie jej wywołania, a nie w miejscu jej definicji.
Wyróżniamy trzy sposoby wywołania funkcji, które zmieniają wartość kontekstu funkcji.
Wywołanie funkcji jako…
…metoda obiektu
Funkcja, która została wywołana na obiekcie przyjmuje wartość this tego obiektu np.
const vehicle = {
speed: 100,
getSpeed() {
// this = vehicle
return this.speed;
},
};
vehicle.getSpeed(); // 100Wywołanie metody getSpeed obiektu vehicle wskazuje kontekst na obiekt vehicle.
Fragment kodu który decyduje o kontekście funkcji getSpeed:
vehicle.getSpeed();…wartość zmiennej
Korzystając z poprzedniego przykładu, wywołamy metodę getSpeed nie jako właściwość obiektu vehicle, lecz jako funkcja, którą przypiszemy do zmiennej.
const vehicle = {
speed: 100,
getSpeed() {
// this = Window / undefined
return this.speed;
},
};
const getVehicleSpeed = vehicle.getSpeed;
getVehicleSpeed(); // undefinedTym razem funkcja getSpeed zamiast oczekiwanej wartości 100 zwróciła undefined. Stało się tak dlatego, ponieważ przypisując funkcję do zmiennej, jednocześnie straciła ona kontekst obiektu vehicle. this wskazuje teraz na inną wartość, którą jest obiekt Window lub wartość undefined w trybie strict.
…konstruktor
Ostatnim sposobem wywołania funkcji, który ustala jej kontekst jest wywołanie jej jako konstruktora za pomocą słowa kluczowego new.
function Vehicle() {
// this = {}
this.speed = 100;
}
const vehicle = new Vehicle();Kontekst this funkcji Vehicle wywołanej jako konstruktor wskazuje na pusty obiekt {}.
Sprawa wygląda identycznie tworząc klasę.
class Vehicle {
constructor() {
// this = {}
this.speed = 100;
}
}
const vehicle = new Vehicle();Funkcje pozwalające modyfikować kontekst
bind()
Tworzy nową funkcję z podanym przez nas kontekstem.
const vehicle = {
speed: 100,
getSpeed() {
// this = vehicle
return this.speed;
},
};
const getVehicleSpeed = vehicle.getSpeed.bind(vehicle);
getVehicleSpeed(); // 100Opcjonalnie przyjmuje również argumenty które zostaną przekazane podczas wywoływania zbindowanej funkcji.
.bind(vehicle, ...argumenty);call()
Wywołuje funkcję z podanym kontekstem, oraz przyjmuje argumenty funkcji jako kolejne parametry.
const vehicle = {
speed: 100,
getSpeed() {
// this = vehicle
return this.speed;
},
};
const getVehicleSpeed = vehicle.getSpeed;
getVehicleSpeed.call(vehicle, ...argumenty); // 100apply()
Podobnie jak funkcja call() wywołuje funkcję z podanym kontekstem, oraz przyjmuje argumenty, nie podajemy ich jednak jako kolejne parametry lecz są one w postaci tablicy.
const vehicle = {
speed: 100,
getSpeed() {
// this = vehicle
return this.speed;
},
};
const getVehicleSpeed = vehicle.getSpeed;
getVehicleSpeed.apply(vehicle, [...argumenty]); // 100Podsumowanie
Podsumowując, kontekst w JavaScript nie zależy od miejsca / sposobu w jaki została zdefiniowana, lecz od sposobu jej wywołania.