Wynik funkcji (hoisting?)

0

Mam taki skrypt:

var x = 3;

var foo = {
    x: 2,
    baz: {
        x: 1,
        bar: function() {
            return this.x;
        }
    }
}

var go = foo.baz.bar;

alert(go());
alert(foo.baz.bar());

Nie do końca rozumiem dlaczego wynik jest "3,1"

Wydawało mi się, że wynikiem będzie " 1 , 2 ". Mógłby mi ktoś to wyjaśnić? Nie daje mi to spokoju

2

Chodzi o kontekst wywołania.

Zmiennej go przypisałeś funkcję foo.baz.bar, którą następnie wywołałeś globalnie, a co za tym idzie this nie wskazywał na foo.baz.x, a na x znaleziony w głównym scope'ie. Gdyby x nie było w globalnej przestrzeni dostałbyś undefined.

Natomiast wywołanie bezpośrednie foo.baz.bar() scope ma umiejscowiony wewnątrz foo.baz, zatem this wskazuje na x o wartości 1.

1

funkcje w JS nie wiążą się automatycznie do obiektów.
masz funkcję i jeśli ją wyrwiesz z obiektu, to jest to zwykła funkcja. Możesz ją wywołać, albo podczepić do innego obiektu, np.
innyObiekt.staraFunkcja = staryObiekt.staraFunkcja

. Ale też wtedy musisz napisać tak: innyObiekt.staraFunkcja() żeby JS załapał, do którego obiektu należy funkcja. Funkcje luzem nie mają podczepionego this...

...poza przypadkami kiedy mają ;)
jeśli użyłbyś metody call albo apply to mógłbyś napisać:

go.call(foo.baz)

czyli uruchom funkcję w kontekście obiektu foo.baz (który dla tego konkretnego wywołania stanie się takim this dla tej funkcji).

jeszcze jest metoda bind, która trwale wiąże kontekst, np.

var go = foo.baz.bar.bind(foo.baz);
alert(go()); // powinno być już 1
0

@Xoxepin:

Operator pamięci (kropka i nawiasy kwadratowe), przypisują rodzica do this poprzez referencję podczas wywołania funkcji.
Innymi słowy this nie wskazuje na nic póki nie wywołamy funkcji.

Przykład:

var mojObiekt = {nazwa: 'to jest moja nazwa'}
mojObiekt.mojaNowaFunkcja = function () {
    console.log(this.nazwa)
}
mojObiekt.mojaNowaFunkcja() 
/*
Wydrukuje do konsoli "to jest moja nazwa", dlatego że operator pamięci (czyli kropka) przypisuje mojObiekt jako this w mojaNowaFunkcja.
*/

Jeśli nie używamy operatora pamięci przy wywołaniu funkcji, to this domyślnie wskazuje na obiekt globalny, którego dziećmi (parametrami) są zmienne globalne.

Jeśli mamy zmienną

var x = 10

To w przeglądarce możemy się do niej dostać na 3 sposoby. Wpisując "x", "window.x" lub "window['x']. Jak widać, x jest parametrem obiektu window, który w przeglądarce jest obiektem globalnym. W NodeJS obiekt globalny nazwa się global.

0

Innymi słowy this nie wskazuje na nic póki nie wywołamy funkcji.

W wyjątkiem, gdy wskazuje - gdy ręcznie określimy kontekst (bind).

Operatory pamięci (kropka i nawiasy kwadratowe), przypisują rodzica do this poprzez referencję podczas wywołania funkcji.

Z wyjątkiem, gdy nie przypisują - w przypadku zbindowanego kontekstu lub arrow function.

Ogólnie to wyjaśnienie z operatorem pamięci (cokolwiek to jest) jest taką kulawą regułą kciuka. Nie wiem po co ją wprowadzać, gdy tak naprawdę wszystko rozbija się o kontekst wywołania (który może być ustawiony ręcznie lub określony automatycznie). Btw reguły te są mocno zagmatwane, najlepiej po prostu zapoznać się z dokumentacją https://developer.mozilla.org[...]ript/Reference/Operators/this lub przeczytać rozdział podlinkowany przez @mch0588

A na koniec jak już się zrozumie, to przestać używać this w swoim kodzie :P

0

@Maciej Cąderek:
Uznałem że bind, call i lambdy to zbyt duża ilość informacji na start.
Tak naprawdę to od Twojej zasady też są wyjątki, dlatego że w lambdach this jest zescopowany leksykalnie.

W strict mode z kolei , liczy się tylko kontekst egzekucyjny.
Możemy wymyślać całą masę innych wyjątków, ale IMHO chodzi o to by koledze dać jakąś wstępną intuicję jak to działa.

0

@Michael Kurowski

Tak naprawdę to od Twojej zasady też są wyjątki

Ale ja nie podałem konkretnej zasady, podałem kontrprzykłady i odesłałem do dokumentacji ;)

chodzi o to by koledze dać jakąś wstępną intuicję jak to działa

Czy upraszczanie to dobra droga do wytłumaczenia tego? Nie wiem, być może.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0