2013-02-23 13 views
9

Nie mogę sobie poradzić z konkretnym przypadkiem wyznaczania zmiennych JavaScript. W odróżnieniu od innych przykładów i pytań, które znalazłem, interesuję się zasięgiem zagnieżdżonych funkcji.Skalowanie lokalne lokacji lokalnej: var vs.

Podałem przykład pod adresem this JSFiddle. Właściwa część jest następująca:

function MyObject() { 
    var self = this; 

    var a = 1; 
    this.b = 2; 

    var innerMethod = function() { 
     //1 and 2: direct reference 
     logMessage("a = " + a); // a = 1 
     //logMessage("b = " + b); // Error: b is not defined 

     //3 and 4: using this 
     logMessage("this.a = " + this.a); // this.a = undefined 
     logMessage("this.b = " + this.b); // this.b = undefined 

     //5 and 6: using self 
     logMessage("self.a = " + self.a); // self.a = undefined 
     logMessage("self.b = " + self.b); // self.b = 2 
    } 
} 

Teraz rozumiem, że odniesienie do a działa bezpośrednio. Rozumiem również, że komunikaty 3 i 4 (this.a i this.b) nie powiodą się, ponieważ this odnosi się do funkcji wewnętrznej. Rozumiem również, że wiersz 6 działa, ponieważ zapisuję odniesienie do oryginalnego obiektu.

Co ja nie rozumiem:

  • dlaczego nie są komunikaty 1 i 2 pracują jednakowo?
  • dlaczego wiadomości 5 i 6 nie działają tak samo?
+5

Dlaczego mieliby działać podobnie? Wygląda na to, że robisz analogię z Javą lub jakimś innym językiem, w którym "this" przestrzeń nazw jest niejawna, co nie ma miejsca w przypadku JS. –

+0

@ FabrícioMatté Mogę być nieprzytomny robiąc to (kalambur przeznaczony). Nie rozumiem, czy zakresy powinny automatycznie wystawiać zmienne/członków na członków wewnętrznych. Wygląda na to, że tak nie jest, ponieważ nie jest spójny. – Alpha

+3

@Alpha Porównywasz zmienne ('var a = 5;') z rzeczami, które nie są zmiennymi, ale właściwościami obiektów ('this.b = 10;' ustawia właściwość 'b' obiektu, który' this' odnosi do "10"). Te rzeczy nie są takie same i dlatego nie zachowują się identycznie. – Niko

Odpowiedz

4

Zmienna a jest właśnie taka, zmienna. Jest on widoczny w zakresie innerMethod (który jest po prostu funkcją zagnieżdżoną), jako a, czyli w jaki sposób został zadeklarowany (tj. JavaScript ma leksykalne reguły zasięgu, wewnętrzne funkcje mogą zobaczyć zmienne funkcji, które są zdefiniowane wewnątrz).

this to nie to samo, co lokalny zakres konstruktora MyObject.

Widzieliście że self jest aliasem dla this z MyObject i że innerMethod został nadpisany this we własnym zakresie. Mimo to, ponieważ this nie jest aliasem dla zakresu funkcji, ani self.a, ani this.a nigdy tutaj nie będzie działać.

Bardziej rygorystyczne wyjaśnienie zakresu leksykalnego można np. rozpocząć w Wikipedii: http://en.wikipedia.org/wiki/Scope_(computer_science)

Można przeczytać o kontekstach egzekucyjnych i zasad rozstrzygania identyfikator w ECMA standardowych http://es5.github.com/#x10.3

+0

Dobrze wyjaśnione. :) – Kaeros

+0

Wolałbym termin ['VariableEnvironment'] (http://es5.github.com/#x10.3) zamiast" function scope "w twoim trzecim akapicie, i stwierdzam, że powód pierwszego akapitu jest to, że JS ma [zakres leksykalny] (http://stackoverflow.com/questions/1047454/what-is-lexical-scope). Ale bardzo dobrze wyjaśnione. –

+0

Włączyłem niektóre z twoich zmian, ale jestem niezdecydowany, aby wymienić VariableEnvironment dla zakresu funkcji. Chociaż jest technicznie poprawniejszy, uważam, że zakres funkcji jest pojęciem, które jest lepiej znane programistom pochodzącym z innych języków. Dodałem twój link do standardu ECMA. – thebjorn

1

Jest to problem z zakresem, kiedy tworzone są funkcje, zapisują one otoczenie (w tym zmienne).

Po utworzeniu innerMethod może wyświetlić zmienne self i a.

Ważną koncepcją jest to, że zakres jest tworzony, gdy funkcja jest zadeklarowana, a nie kiedy jest wywoływana.

W twoim przypadku 1, b nie jest zadeklarowany (ten obiekt nie jest taki sam).

W przypadkach 5 i 6 nie utworzono self.a.

0

Głównym powodem jest to, że self nie jest równa this w zakresie innerMethod. this jest słowem kluczowym wskazującym właściciela tej funkcji.Dla innerMethod, NIE jest to metoda instancji, należy do Okna.

function MyObject() { 
    var self = this; 

    var innerMethod = function() { 
     alert("inner method, self == this?: " + self == this); // false 
     alert("inner method: " + this); // [object Window] 
     alert("closest constructor name of in prototype chain ?: "+ this.__proto__.constructor.name); // Window 
    } 

    this.outerMethod = function(){ 
     innerMethod(); 
     alert("outer method: " + this); // [object MyObject] 
     alert("closest constructor name in prototype chain?: "+ this.__proto__.constructor.name); // MyObject 
    } 
} 

var o = new MyObject(); 
o.outerMethod(); 

Można grać na here