Mam pytanie dotyczące sposobu traktowania wskaźnika „this” w scenariuszu funkcji zagnieżdżonej.
Powiedzmy, że wstawiam następujący przykładowy kod na stronę internetową. Gdy wywołuję zagnieżdżoną funkcję „doSomeEffects ()”, pojawia się błąd. Sprawdziłem w Firebug i wskazuje, że kiedy jestem w tej zagnieżdżonej funkcji, wskaźnik „this” w rzeczywistości wskazuje na globalny obiekt „window” - czego się nie spodziewałem. Nie mogę rozumieć czegoś poprawnie, ponieważ pomyślałem, że skoro zadeklarowałem zagnieżdżoną funkcję w funkcji obiektu, powinna mieć zasięg „lokalny” w stosunku do funkcji (tj. Wskaźnik „ten” odnosiłby się do samego obiektu jak jak to jest w moim pierwszym stwierdzeniu „jeśli”).
Wszelkie wskazówki (gra słów nie przeznaczona) będą mile widziane.
var std_obj = {
options : { rows: 0, cols: 0 },
activeEffect : "none",
displayMe : function() {
// the 'this' pointer is referring to the std_obj
if (this.activeEffect=="fade") { }
var doSomeEffects = function() {
// the 'this' pointer is referring to the window obj, why?
if (this.activeEffect=="fade") { }
}
doSomeEffects();
}
};
std_obj.displayMe();
źródło
this
odnosi się do obiektu, dla którego funkcja jest wywoływana.var self = this;
a następnie odnosić się doself
funkcji wewnętrznej poprzez zamknięcie.doSomeEffects
nie jest powiązany z żadnym konkretnym obiektem, więcthis
zakłada się, że jest oknem, matką wszystkich elementów.Odpowiedzi:
W JavaScript
this
obiekt jest tak naprawdę oparty na sposobie wywoływania funkcji.Ogólnie rzecz biorąc, istnieją trzy sposoby konfiguracji
this
obiektu:someThing.someFunction(arg1, arg2, argN)
someFunction.call(someThing, arg1, arg2, argN)
someFunction.apply(someThing, [arg1, arg2, argN])
We wszystkich powyższych przykładach
this
obiektem będziesomeThing
. Wywołanie funkcji bez wiodącego obiektu nadrzędnego generalnie da ci obiekt globalny, który w większości przeglądarek oznaczawindow
obiekt.źródło
this.doSomeEffects();
oparty na Twojej odpowiedzi, ale nadal nie działa. Czemu?this
wthis.doSomeEffects()
wskazuje nastd_obj
. Jak wyjaśniono w powyższej odpowiedzi, jeśli funkcja nie ma odniesienia do obiektu,this
musi być obiektem okna.Ponieważ wydaje się, że jest to jedno z najbardziej opiniotwórczych pytań tego rodzaju, pozwolę sobie dodać po tych wszystkich latach rozwiązanie ES6 wykorzystujące funkcje strzałkowe:
var std_obj = { ... displayMe() { ... var doSomeEffects = () => { ^^^^^^^ ARROW FUNCTION // In an arrow function, the 'this' pointer is interpreted lexically, // so it will refer to the object as desired. if (this.activeEffect=="fade") { } }; ... } };
źródło
this
nie jest częścią zakresu zamknięcia, może być traktowany jako dodatkowy parametr funkcji, która jest powiązana w miejscu wywołania. Jeśli metoda nie zostanie wywołana jako metoda, obiekt globalny jest przekazywany jakothis
. W przeglądarce obiekt globalny jest identyczny zwindow
. Weźmy na przykład pod uwagę następującą funkcję,function someFunction() { }
i następujący przedmiot,
var obj = { someFunction: someFunction };
Jeśli wywołasz funkcję przy użyciu składni metody, takiej jak,
wtedy
this
jest zobowiązanyobj
.Jeśli wywołasz funkcję someFunction () bezpośrednio, na przykład
to
this
znaczy jest powiązany z obiektem globalnymwindow
.Najczęstszym sposobem obejścia tego problemu jest uwzględnienie tego w zamknięciu, na przykład
displayMe : function() { // the 'this' pointer is referring to the std_obj if (this.activeEffect=="fade") { } var that = this; var doSomeEffects = function() { // the 'this' pointer is referring to global // that, however, refers to the outscope this if (that.activeEffect=="fade") { } } doSomeEffects(); }
źródło
Istnieje różnica między zmiennymi obejmującymi a „to”. „this” jest w rzeczywistości definiowane przez wywołującego funkcję, podczas gdy jawne zmienne pozostają nienaruszone wewnątrz bloku deklaracji funkcji, zwanego obudową. Zobacz poniższy przykład:
function myFirstObject(){ var _this = this; this.name = "myFirstObject"; this.getName = function(){ console.log("_this.name = " + _this.name + " this.name = " + this.name); } } function mySecondObject(){ var _this = this; this.name = "mySecondObject"; var firstObject = new myFirstObject(); this.getName = firstObject.getName } var secondObject = new mySecondObject(); secondObject.getName();
możesz to wypróbować tutaj: http://jsfiddle.net/kSTBy/
To, co dzieje się w Twojej funkcji, to „doSomeEffects ()”, jest wywoływane jawnie, co oznacza, że kontekst lub „this” funkcji to okno. jeśli „doSomeEffects” było metodą prototypową, np. this.doSomeEffects na powiedz „myObject”, to myObject.doSomeEffects () spowoduje, że „this” będzie „myObject”.
źródło
_this.name = myFirstObject this.name = mySecondObject
Aby zrozumieć to pytanie, spróbuj uzyskać dane wyjściowe dla następującego fragmentu kodu
var myObject = { foo: "bar", func: function() { var self = this; console.log("outer func: this.foo = " + this.foo); console.log("outer func: self.foo = " + self.foo); (function() { console.log("inner func: this.foo = " + this.foo); console.log("inner func: self.foo = " + self.foo); }()); } }; myObject.func();
Powyższy kod wyświetli na konsoli następujący kod:
outer func: this.foo = bar outer func: self.foo = bar inner func: this.foo = undefined inner func: self.foo = bar
W zewnętrznej funkcji zarówno this, jak i self odnoszą się do myObject i dlatego oba mogą poprawnie odwoływać się do foo i uzyskiwać do niego dostęp.
Jednak w funkcji wewnętrznej nie odnosi się to już do myObject. W rezultacie this.foo jest niezdefiniowane w funkcji wewnętrznej, podczas gdy odwołanie do zmiennej lokalnej self pozostaje w zakresie i jest tam dostępne. (Przed ECMA 5, to w funkcji wewnętrznej odnosiłoby się do globalnego obiektu okna; podczas gdy od ECMA 5, w funkcji wewnętrznej byłoby niezdefiniowane).
źródło
this
odnosi się do obiektu okna (w środowisku przeglądarki) lub obiektu GLOBAL (w środowisku node.js)this
nie odnosi się już do oknaJak wyjaśnił Kyle, możesz użyć
call
lubapply
do określeniathis
w funkcji:Oto koncepcja zastosowana do twojego kodu:
var std_obj = { options: { rows: 0, cols: 0 }, activeEffect: "none", displayMe: function() { // the 'this' pointer is referring to the std_obj if (this.activeEffect == "fade") {} var doSomeEffects = function() { // the 'this' pointer is referring to the window obj, why? if (this.activeEffect == "fade") {} } doSomeEffects.apply(this,[]); } }; std_obj.displayMe();
JsFiddle
źródło
Otrzymałem również ostrzeżenie „ Potencjalnie nieprawidłowy dostęp do odwołania do pola klasy za pośrednictwem tego ”
class MyListItem { constructor(labelPrm) { this._flagActive = false; this._myLabel = labelPrm; labelPrm.addEventListener('click', ()=>{ this.onDropdownListsElementClick();}, false); } get myLabel() { return this._myLabel } get flagActive(){ return this._flagActive; } onDropdownListsElementClick(){console.log("Now'this'refers to the MyListItem itself")}}//end of the class
źródło
Ponieważ nie zostało to wspomniane, wspomnę, że używanie
.bind()
jest rozwiązaniem -doSomeEffects=doSomeEffect.bind(this); doSomeEffects(); } }; std_obj.displayMe();
Oto prostszy przykład -
bad = { name:'NAME', z : function() { function x() { console.log(this.name); }; x() } }; bad.z() // prints 'undefined' good = { name:'NAME', z : function() { function x() { console.log(this.name); }; x=x.bind(this); x(); } }; good.z() // prints 'NAME'
Prawdą jest, że używanie funkcji strzałek
=>
wygląda na bardziej przejrzyste i łatwe dla programisty. Należy jednak pamiętać, że zakres leksykalny będzie prawdopodobnie wymagał więcej pracy pod względem przetwarzania i pamięci, aby ustawić i utrzymać ten zakres leksykalny, w porównaniu do zwykłego powiązania funkcjithis
ze wskaźnikiem za pomocą.bind()
.Częścią korzyści z tworzenia klas w JS było zapewnienie metody do wykonania
this
bardziej niezawodnej prezentacji i dostępności, aby odejść od programowania funkcjonalnego i zakresów leksykalnych, a tym samym zmniejszyć narzut.Z MDN
źródło