Co powinieneś wiedzieć this
this(aka „kontekst”) jest specjalnym słowem kluczowym wewnątrz każdej funkcji, a jej wartość zależy tylko od tego, jak funkcja została wywołana, a nie jak / kiedy / gdzie została zdefiniowana. Nie ma na to wpływu zakresy leksykalne, takie jak inne zmienne (z wyjątkiem funkcji strzałek, patrz poniżej). Oto kilka przykładów:
function foo() {
console.log(this);
}
// normal function call
foo(); // `this` will refer to `window`
// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`
// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`
Aby dowiedzieć się więcej, zapoznaj się thisz dokumentacją MDN .
Jak odnieść się do prawidłowego this
Nie używaj this
W rzeczywistości nie chcesz thisw szczególności uzyskiwać dostępu , ale obiekt, do którego się odnosi . Dlatego łatwym rozwiązaniem jest po prostu utworzenie nowej zmiennej, która również odnosi się do tego obiektu. Zmienna może mieć dowolną nazwę, ale typowymi są selfi that.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Ponieważ selfjest to normalna zmienna, jest zgodna z zasadami zakresu leksykalnego i jest dostępna w wywołaniu zwrotnym. Ma to również tę zaletę, że można uzyskać dostęp do thiswartości samego wywołania zwrotnego.
Jawnie ustawiony zestaw thiszwrotny - część 1
Może się wydawać, że nie masz kontroli nad wartością, thisponieważ jego wartość jest ustawiana automatycznie, ale tak naprawdę nie jest.
Każda funkcja ma metodę .bind [docs] , która zwraca nową funkcję thispowiązaną z wartością. Ta funkcja działa dokładnie tak samo jak ta, którą wywołałeś .bind, tyle że thiszostała ustawiona przez ciebie. Bez względu na to, jak i kiedy ta funkcja jest wywoływana, thiszawsze będzie odnosić się do przekazanej wartości.
function MyConstructor(data, transport) {
this.data = data;
var boundFunction = (function() { // parenthesis are not necessary
alert(this.data); // but might improve readability
}).bind(this); // <- here we are calling `.bind()`
transport.on('data', boundFunction);
}
W takim przypadku wiążemy wywołania zwrotne thisz wartością MyConstructor's this.
Uwaga: Podczas wiązania kontekstu dla jQuery użyj zamiast tego jQuery.proxy [docs] . Powodem tego jest to, że nie trzeba przechowywać odwołania do funkcji podczas rozpakowywania wywołania zwrotnego zdarzenia. jQuery obsługuje to wewnętrznie.
ECMAScript 6 wprowadza funkcje strzałek , które można traktować jako funkcje lambda. Nie mają własnego thiswiązania. Zamiast tego thisjest sprawdzany w zakresie jak normalna zmienna. Oznacza to, że nie musisz dzwonić .bind. To nie jedyne specjalne zachowanie, jakie mają. Więcej informacji można znaleźć w dokumentacji MDN.
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => alert(this.data));
}
Zestaw thisoddzwaniania - część 2
Niektóre funkcje / metody, które akceptują wywołania zwrotne, akceptują również wartość, do której thispowinny się odnosić wywołania zwrotne . Jest to w zasadzie to samo, co samodzielne wiązanie, ale funkcja / metoda robi to za Ciebie. Array#map [docs] jest taką metodą. Jego podpis to:
array.map(callback[, thisArg])
Pierwszy argument to wywołanie zwrotne, a drugi argument to wartość, do której thisnależy się odwoływać. Oto wymyślony przykład:
var arr = [1, 2, 3];
var obj = {multiplier: 42};
var new_arr = arr.map(function(v) {
return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument
Uwaga: To, czy możesz przekazać wartość, thisjest zwykle wspomniane w dokumentacji tej funkcji / metody. Na przykład metoda jQuery [docs]$.ajax opisuje opcję o nazwie context:
Ten obiekt stanie się kontekstem wszystkich wywołań zwrotnych związanych z Ajax.
Typowy problem: używanie metod obiektowych jako wywołań zwrotnych / procedur obsługi zdarzeń
Innym częstym przejawem tego problemu jest użycie metody obiektowej jako funkcji obsługi wywołania zwrotnego / zdarzenia. Funkcje są pierwszorzędnymi obywatelami w JavaScript, a termin „metoda” jest tylko terminem potocznym dla funkcji, która jest wartością właściwości obiektu. Ale ta funkcja nie ma konkretnego łącza do jej „zawierającego” obiektu.
Rozważ następujący przykład:
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = function() {
console.log(this.data);
};
Funkcja this.methodjest przypisany jako obsługi zdarzenia kliknięcia, ale jeśli document.bodyzostanie kliknięty, wartość zalogowany będzie undefined, ponieważ wewnątrz obsługi zdarzeń, thisodnosi się do document.body, a nie instancji Foo.
Jak już wspomniano na początku, to, do czego się thisodnosi, zależy od tego, jak funkcja jest wywoływana , a nie jak jest zdefiniowana .
Jeśli kod wyglądał następująco, może być bardziej oczywiste, że funkcja nie ma niejawnego odwołania do obiektu:
function method() {
console.log(this.data);
}
function Foo() {
this.data = 42,
document.body.onclick = this.method;
}
Foo.prototype.method = method;
Rozwiązanie jest takie samo jak wspomniane powyżej: jeśli jest dostępne, użyj, .bindaby jawnie powiązać thisz określoną wartością
document.body.onclick = this.method.bind(this);
lub jawnie wywołać funkcję jako „metodę” obiektu, używając funkcji anonimowej jako funkcji obsługi wywołania zwrotnego / zdarzenia i przypisując obiekt ( this) do innej zmiennej:
var self = this;
document.body.onclick = function() {
self.method();
};
lub użyj funkcji strzałki:
document.body.onclick = () => this.method();