Mam funkcję konstruktora, która rejestruje moduł obsługi zdarzeń:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', function () {
alert(this.data);
});
}
// Mock transport object
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// called as
var obj = new MyConstructor('foo', transport);
Nie mogę jednak uzyskać dostępu do data
właściwości utworzonego obiektu w wywołaniu zwrotnym. Wygląda na to, this
że nie odnosi się do obiektu, który został stworzony, ale do innego.
Próbowałem także użyć metody obiektowej zamiast funkcji anonimowej:
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', this.alert);
}
MyConstructor.prototype.alert = function() {
alert(this.name);
};
ale wykazuje te same problemy.
Jak mogę uzyskać dostęp do właściwego obiektu?
javascript
callback
this
Felix Kling
źródło
źródło
Odpowiedzi:
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: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
ithat
.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 dothis
wartości samego wywołania zwrotnego.Jawnie ustawiony zestaw
this
zwrotny - część 1Moż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 żethis
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.W takim przypadku wiążemy wywołania zwrotne
this
z wartościąMyConstructor
'sthis
.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: Użyj funkcji strzałek
ECMAScript 6 wprowadza funkcje strzałek , które można traktować jako funkcje lambda. Nie mają własnego
this
wiązania. Zamiast tegothis
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.Zestaw
this
oddzwaniania - część 2Niektó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: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: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 nazwiecontext
: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:
Funkcja
this.method
jest przypisany jako obsługi zdarzenia kliknięcia, ale jeślidocument.body
zostanie kliknięty, wartość zalogowany będzieundefined
, ponieważ wewnątrz obsługi zdarzeń,this
odnosi się dodocument.body
, a nie instancjiFoo
.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:
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ą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:lub użyj funkcji strzałki:
źródło
self
ithat
do których można się odwoływaćthis
. Czuję się tak, ponieważthis
przeciążona zmienna jest używana w różnych kontekstach; podczas gdyself
zwykle odpowiada lokalnej instancji ithat
zwykle odnosi się do innego obiektu. Wiem, że nie ustawiłeś tej zasady, ponieważ widziałem, jak pojawia się ona w wielu innych miejscach, ale właśnie dlatego zacząłem ją stosować_this
, ale nie jestem pewien, jak się czują inni, z wyjątkiem niejednolitej praktyki to spowodowało.Function.prototype.call ()
iFunction.prototype.apply ()
. Szczególnie zapply ()
że mam duży przebieg. Jestem mniej skłonny do używaniabind ()
być może tylko z przyzwyczajenia, chociaż zdaję sobie sprawę (ale nie jestem pewien), że korzystanie z opcji wiązania w porównaniu z innymi opcjami może mieć niewielkie zalety.() => this.clicked()
;)Oto kilka sposobów dostępu do kontekstu nadrzędnego w kontekście potomnym -
bind()
funkcji.1. Użyj
bind()
funkcjiJeśli używasz
underscore.js
- http://underscorejs.org/#bind2 Zapisz odniesienie do kontekstu / tego w innej zmiennej
3 Funkcja strzałki
źródło
Wszystko opiera się na „magicznej” składni wywołania metody:
Kiedy pobierzesz właściwość z obiektu i wywołasz ją za jednym razem, obiekt będzie kontekstem dla metody. Jeśli wywołasz tę samą metodę, ale w oddzielnych krokach, kontekstem będzie zasięg globalny (okno):
Kiedy otrzymasz referencję do metody, nie jest ona już dołączona do obiektu, jest to tylko odwołanie do prostej funkcji. To samo dzieje się, gdy otrzymasz odwołanie do użycia jako oddzwonienia:
W tym miejscu powiąż kontekst z funkcją:
Jeśli używasz jQuery, powinieneś użyć
$.proxy
metody, ponieważbind
nie jest obsługiwana we wszystkich przeglądarkach:źródło
Problem z „kontekstem”
Termin „kontekst” jest czasem używany w odniesieniu do obiektu, do którego się to odnosi . Jego zastosowanie jest niewłaściwe, ponieważ nie pasują zarówno semantycznie lub technicznie z ECMAScript na to .
„Kontekst” oznacza okoliczności otaczające coś, co dodaje znaczenie, lub niektóre informacje poprzedzające i następujące po nim, które nadają dodatkowe znaczenie. Termin „kontekst” jest używany w ECMAScript w odniesieniu do kontekstu wykonania , który obejmuje wszystkie parametry, zakres i to w zakresie części wykonywanego kodu.
Jest to pokazane w ECMA-262 sekcja 10.4.2 :
który wyraźnie wskazuje, że to jest częścią kontekstu wykonania.
Kontekst wykonania zapewnia otaczające informacje, które nadają znaczenie wykonywanemu kodowi. Zawiera znacznie więcej informacji niż tylko to wiązanie .
Zatem wartością tego nie jest „kontekst”, to tylko jedna część kontekstu wykonania. Zasadniczo jest to zmienna lokalna, którą można ustawić przez wywołanie dowolnego obiektu i w trybie ścisłym dowolnej wartości.
źródło
this
ale żaden nie jest tu oferowany i prawdopodobnie jest już za późno, aby zamknąć drzwi w „kontekście”.Powinieneś wiedzieć o „tym” słowie kluczowym.
Zgodnie z moim poglądem możesz to „wdrożyć” na trzy sposoby (Self / Funkcja strzałki / Metoda wiązania)
Funkcja to słowo kluczowe zachowuje się nieco inaczej w JavaScript w porównaniu do innych języków.
Ma także pewne różnice między trybem ścisłym a trybem ścisłym.
W większości przypadków wartość tego zależy od sposobu wywołania funkcji.
Nie można go ustawić przez przypisanie podczas wykonywania i może być inny przy każdym wywołaniu funkcji.
ES5 wprowadził metodę bind () w celu ustawienia wartości funkcji niezależnie od tego, jak się nazywa,
i ES2015 wprowadził funkcje strzałek, które nie zapewniają tego powiązania (zachowuje tę wartość otaczającego kontekstu leksykalnego).
Metoda 1: Jaźń jest używana do zachowania odniesienia do oryginału, nawet gdy zmienia się kontekst. Jest to technika często stosowana w procedurach obsługi zdarzeń (szczególnie w zamknięciach).
Odniesienie : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
Metoda 2 : Funkcja strzałki - wyrażenie funkcji strzałki jest zwartą składniowo alternatywą dla wyrażenia funkcji regularnej,
chociaż bez własnych powiązań z tym, argumentami, super lub new.target słowami kluczowymi.
Wyrażenia funkcji strzałek źle nadają się na metody i nie można ich używać jako konstruktorów.
Odniesienie : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Method3 : Bind- Metoda bind () tworzy nową funkcję, która:
po wywołaniu ma to słowo kluczowe ustawione na podaną wartość,
z podaną sekwencją argumentów poprzedzającą dowolną podaną podczas wywoływania nowej funkcji.
Odniesienie: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind
źródło
Po pierwsze, musisz dobrze rozumieć
scope
i zachowywaćthis
słowa kluczowe w kontekściescope
.this
Iscope
:w skrócie, zakres globalny odnosi się do obiektu okna. Zmienne zadeklarowane w zasięgu globalnym są dostępne z dowolnego miejsca. Z drugiej strony zakres funkcji znajduje się wewnątrz funkcji. zmienna zadeklarowana wewnątrz funkcji nie jest normalnie dostępna z zewnątrz.
this
słowo kluczowe w zasięgu globalnym odnosi się do obiektu okna.this
funkcja wewnętrzna odnosi się również do obiektu oknathis
, więc zawsze będzie odnosić się do okna, dopóki nie znajdziemy sposobu na manipulację wthis
celu wskazania kontekstu, który sam wybieramy.Różne sposoby manipulowania
this
funkcjami wywołania zwrotnego:Tutaj mam funkcję konstruktora o nazwie Osoba. Posiada właściwość o nazwie
name
i cztery metody zwanejsayNameVersion1
,sayNameVersion2
,sayNameVersion3
,sayNameVersion4
. Wszystkie cztery mają jedno konkretne zadanie. Zaakceptuj wywołanie zwrotne i wywołaj je. Oddzwonienie ma określone zadanie polegające na zarejestrowaniu właściwości name wystąpienia funkcji konstruktora Person.Teraz stwórzmy instancję z konstruktora person i wywołajmy różne wersje metody
sayNameVersionX
(X odnosi się do 1,2,3,4),niceCallback
aby zobaczyć, na ile sposobów możemy manipulowaćthis
wewnętrznym wywołaniem zwrotnym, aby odwoływać się doperson
instancji.wiążą:
Wiązanie polega na utworzeniu nowej funkcji za pomocą
this
słowem kluczowym ustawionym na podaną wartość.sayNameVersion1
isayNameVersion2
użyj bind do manipulowaniathis
funkcją wywołania zwrotnego.pierwszy wiąże się
this
z wywołaniem zwrotnym w samej metodzie, a drugi jest przekazywany z powiązanym obiektem.połączenie :
first argument
Odcall
sposobu stosuje sięthis
wewnątrz funkcji, które są wywoływane zcall
nim związane.sayNameVersion3
służycall
do manipulowania,this
aby odwoływać się do obiektu osoby, który stworzyliśmy, zamiast obiektu okna.i nazywa się to następująco:
zastosować :
Podobnie jak
call
pierwszy argument parametruapply
odnosi się do obiektu, który będzie wskazywany przezthis
słowo kluczowe.sayNameVersion4
służyapply
do manipulowaniathis
odniesieniem do obiektu osobyi nazywa się to następująco: po prostu wywołanie zwrotne zostało przekazane,
źródło
Nie możemy tego powiązać
setTimeout()
, ponieważ zawsze wykonuje się to za pomocą globalnego obiektu (Window) , jeśli chcesz uzyskać dostępthis
kontekstu w funkcji wywołania zwrotnego, to używającbind()
funkcji wywołania zwrotnego możemy osiągnąć jako:źródło
Pytanie dotyczy
this
zachowania słowa kluczowego w javascript.this
zachowuje się inaczej niż poniżej,this
jest zwykle określana przez kontekst wykonywania funkcji.this
odnosi się do obiektu globalnego (window
obiektu).this
będzieundefined
jak w trybie ścisłym, globalny obiekt odnosi sięundefined
w miejscuwindow
obiektu.call()
,bind()
iapply()
new
używane jest słowo kluczowe (konstruktor), jest ono powiązane z tworzonym nowym obiektem.this
-this
są powiązane leksykalnie (tzn. W oparciu o oryginalny kontekst)Jak sugeruje większość odpowiedzi, możemy użyć funkcji strzałki lub
bind()
metody lub własnego var. Chciałbym zacytować punkt o lambdas (funkcja strzałki) z Przewodnika po stylu Google JavaScriptGoogle wyraźnie zaleca stosowanie lambdas zamiast wiązania lub
const self = this
Najlepszym rozwiązaniem byłoby użycie lambd jak poniżej,
Bibliografia:
źródło
this
słowa kluczowego, dlatego podzieliłem moją odpowiedź na dwie części, jedną othis
drugiej, a drugą dotyczącą używania funkcji / metod jako wywołań zwrotnych. Edytuj odpowiedź.Obecnie możliwe jest inne podejście, jeśli klasy są używane w kodzie.
Dzięki obsłudze pól klasowych można to zrobić w następujący sposób:
Na pewno pod maską jest to stara dobra funkcja strzałki, która wiąże kontekst, ale w tej formie wygląda znacznie wyraźniej niż wyraźne wiązanie.
Ponieważ jest to propozycja etapu 3, będziesz potrzebować babel i odpowiedniej wtyczki babel do przetworzenia go jak na razie (08/2018).
źródło
public methodName = (params) => { body }
wewnątrz klasy.Innym podejściem, które jest standardowym sposobem od wiązania przez DOM2
this
w detektorze zdarzeń, który pozwala zawsze usuwać detektor (oprócz innych korzyści), jesthandleEvent(evt)
metoda zEventListener
interfejsu:Szczegółowe informacje na temat korzystania
handleEvent
można znaleźć tutaj: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38źródło
this
w JS:Wartość
this
w JS jest w 100% określona przez to, jak funkcja jest wywoływana, a nie jak jest zdefiniowana. Stosunkowo łatwo możemy znaleźć wartość reguły „this
po lewej stronie kropki” :this
jest obiekt po lewej stronie kropki wywołanej funkcjithis
wewnątrz funkcji jest często obiektem globalnym (global
w węźle,window
w przeglądarce). Nie polecam tutaj używaniathis
słowa kluczowego, ponieważ jest ono mniej wyraźne niż użycie czegoś podobnegowindow
!Function.prototype.bind()
funkcji, które mogą naprawić wartośćthis
. Są to wyjątki od reguły, ale są naprawdę pomocne w ustaleniu wartościthis
.Przykład w węźle JS
Wynik:
Pozwól mi przeprowadzić Cię przez wyjścia 1 na 1 (ignorując pierwszy dziennik, zaczynając od drugiego):
this
zobj2
powodu reguły po lewej stronie kropki, możemy zobaczyć, jaktest1
się nazywaobj2.test1();
.obj2
jest kropką, a zatemthis
wartością.obj2
jest na lewo od kropki,test2
jest związanyobj1
poprzezbind()
metody. Więc…this
wartość wynosiobj1
.obj2
pozostało z kropką z funkcji, które nazywa się:obj2.test3()
. Dlategoobj2
będzie wartośćthis
.obj2.test4()
obj2
pozostało kropki. Jednak funkcje strzałek nie mają własnychthis
wiązania. Dlatego wiąże się zthis
wartością zakresu zewnętrznego, którym jestmodule.exports
obiektem, który został zarejestrowany na początku.this
za pomocącall
funkcji. Tutaj możemy podać żądanąthis
wartość jako argument, coobj2
w tym przypadku.źródło