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ę this
z dokumentacją MDN .
Jak odnieść się do prawidłowego this
Nie używaj this
W rzeczywistości nie chcesz this
w 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ą self
i that
.
function MyConstructor(data, transport) {
this.data = data;
var self = this;
transport.on('data', function() {
alert(self.data);
});
}
Ponieważ self
jest 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 this
wartości samego wywołania zwrotnego.
Jawnie ustawiony zestaw this
zwrotny - część 1
Może się wydawać, że nie masz kontroli nad wartością, this
ponieważ jego wartość jest ustawiana automatycznie, ale tak naprawdę nie jest.
Każda funkcja ma metodę .bind
[docs] , która zwraca nową funkcję this
powiązaną z wartością. Ta funkcja działa dokładnie tak samo jak ta, którą wywołałeś .bind
, tyle że this
została ustawiona przez ciebie. Bez względu na to, jak i kiedy ta funkcja jest wywoływana, this
zawsze 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 this
z 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 this
wiązania. Zamiast tego this
jest 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 this
oddzwaniania - część 2
Niektóre funkcje / metody, które akceptują wywołania zwrotne, akceptują również wartość, do której this
powinny 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 this
należ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ść, this
jest 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.method
jest przypisany jako obsługi zdarzenia kliknięcia, ale jeśli document.body
zostanie kliknięty, wartość zalogowany będzie undefined
, ponieważ wewnątrz obsługi zdarzeń, this
odnosi się do document.body
, a nie instancji Foo
.
Jak już wspomniano na początku, to, do czego się this
odnosi, 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, .bind
aby jawnie powiązać this
z 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();