25maj Tu Haczyk IStnieje – ‘this’ cz. I
W językach programowania słowo kluczowe this wskazuje przeważnie w metodzie na obiekt, w którym jest metoda.
W związku z dynamicznym charakterem JS, fraza this przybiera wartości w zależności od kontekstu w jakim metoda jest wykonana i może być zarówno bardzo pomocne jak i przyprawić o nielichy ból głowy.
W pierwszej części “Tu Haczyk IStnieje” omówie jak zapanować nad this przy użyciu metody bind ulubionego frameworka.
Rozpatrzmy następujący obiekt Car1 z atrybutem color i metodą check zwracającą wartość color:
var Car1 = {
color: "Red",
check: function() {
//console.info(this) - wyświetla wartość w konsoli Firebuga w Firefoxie
alert( "Car color is " + this.color );
}
};
Przypadek 1.
Wywołanie metody check działa tak jak byśmy się spodziewali zwracając Red.
// console.info -> Object color=Red // alert -> Car color is Red Car1.check();
Przypadek 2.
W drugim przypadku możemy być już trochę zaskoczeni, ale w metodzie check – this będzie już wskazywać na Car2, a nie na Car1 i zwróci Blue.
var Car2 = {
color: "Blue",
check: Car1.check
};
//Object color=Blue
//Car color is Blue
Car2.check();
Przypadek 3.
Teraz wywołamy check w kontekście funkcji runFx, która jest metodą obiektu window. Konsekwencją jest to, że color jest undefined.
function runFx(f) {
f();
}
//Window index.html
//Car color is undefined
runFx(Car1.check);
Przypadek 4.
Kolejny przypadek jest podobny do trzeciego jako, że funkcja setTimeout jest wywoływana w kontekście obiektu window, wartość color jest również undefined.
//Window index.html //Car color is undefined setTimeout( Car1.check, 100);
Przypadek 5.
W ostatnim przypadku zamiast funkcji setTimeout, użyłem metody delay i this przybrało wartość function().
//function() //Car color is undefined Car1.check.delay(0.1);
Rozwiązanie czyli bind.
Metoda bind powoduje, że wewnątrz funkcji na której ją wywołamy – this staje się referencją do obiektu, który podamy jako parametr metody bind.
W linii 6. stara funkcja check została zmienionana na _check.
Na koniec w linii 10. wywołujemy pseudo-konstruktor init, w którym this wskazuje na Car1 i dlatego, w linii 3. do check zbindowaliśmy na stałe obiekt Car1.
var Car1 = {
init: function() {
this.check = this._check.bind(this);
},
color: "Red",
_check: function() {
alert( "Car color is " + this.color );
}
};
Car1.init();
Z tak zmienionym obiektem Car1, wszystkie poprzednie pięć przypadków daje ten sam rezultat.
//Object color=Red //Car color is Red Car1.check(); runFx(Car1.check); Car2.check(); setTimeout( Car1.check, 100); Car1.check.delay(0.1);
Ważny bonus do bind
Bind może być również użyte do konstruowania ostatecznej listy parametrów przekazanych do metody. W linii 3. dodajemy wartość initParam, a każdym wywołaniu wartość checkParam.
var Car1 = {
init: function() {
this.check = this._check.bind(this, 'initParam');
},
color: "Red",
_check: function() {
alert($A(arguments).join(', '));
}
};
Car1.init();
Linia 7. powyższego kodu zwraca initParam, checkParam czyli dwa parametry dla każdego wywołania poniżej.
//initParam, checkParam
Car1.check('checkParam');
Car2.check('checkParam');
setTimeout( Car1.check, 500, 'checkParam' );
Car1.check.delay(0.5, 'checkParam');
Podsumowanie
Mam nadzieję, że to wyjaśnienie pomoże zrozumieć działanie this i korzyści jakie ze sobą.
W tej chwili trwają prace nad specyfikację ECMAScript 5 i metoda bind ma wejść do niej, więc za jakiś czas nie będzie zależeć od biblioteki JS, ale od przeglądarek, które będą wspierać ECMAScript 5.





Maj 25th, 2009 at 14:34
„słowo kluczowe this wskazuje _zawsze_ w metodzie na obiekt, w którym jest metoda”
Trochę zbyt mocne to „zawsze”, można przecież wywołać metodę Obiekt.metoda za pomocą Obiekt.metoda.apply (InnyObiekt, argumenty…). Wtedy this będzie wskazywać na InnyObiekt. Właśnie .apply jest używane w .bind.
Maj 25th, 2009 at 14:39
Dzięki za komentarz. Może faktycznie zbyt ogólne i zbyt mocne.
Lipiec 25th, 2010 at 22:32
Dla kogo to napisałeś ? Dla tych co już wiedzą ?
Piszesz na co wskazuje “this” ale DLACZEGO . A MOŻE NIE POTRAFISZ WYTŁUMACZYĆ TĘPAKOM. Nie ukrywam że znakomicie obchodzę sie bez tej wiedzy bo jak się nie wie to zawsze można zapytać funkcji alert() ale mam niedosyt.
Czekam na takie wyjaśnienie żebym w końcu zrozumiał ale pewnie się nie doczekam choć od dawna śledzę w internecie.
Podobne wyjaśnienie znalazłem u Ferrante.
Pozdrawiam !