Zaskakujące, że zmienna globalna ma niezdefiniowaną wartość w JavaScript

Dzisiaj byłem całkowicie zaskoczony, gdy zobaczyłem, że zmienna globalna ma wartość undefined w pewnym przypadku.

Przykład:

var value = 10;
function test() {
    //A
    console.log(value);
    var value = 20;

    //B
    console.log(value);
}
test();

Daje wyjście jako

undefined
20

Tutaj, dlaczego silnik JavaScript traktuje wartość globalną jako undefined. Wiem, że JavaScript jest językiem interpretowanym. Jak można rozpatrywać zmienne w funkcji?

Czy to pułapka z silnika JavaScript?

Author: ubuntugod, 2012-01-31

4 answers

Zjawisko to znane jest jako: JavaScript Variable Hoisting .

W żadnym momencie Nie uzyskujesz dostępu do zmiennej globalnej w swojej funkcji; uzyskujesz tylko dostęp do zmiennej lokalnej value.

Twój kod jest odpowiednikiem:

var value = 10;

function test() {
    var value;
    console.log(value);

    value = 20;
    console.log(value);
}

test();

Nadal zaskoczony, że dostajesz undefined?


Wyjaśnienie:

Jest to coś, na co prędzej czy później wpadnie każdy programista JavaScript. Mówiąc najprościej, niezależnie od zmiennych, które deklarujesz, są zawsze Podnoszone na szczyt twojego lokalnego zamknięcia. Tak więc, nawet jeśli zadeklarowałeś swoją zmienną po pierwszym wywołaniu console.log, nadal jest ona traktowana tak, jakbyś zadeklarował ją wcześniej.
Jednak tylko część deklaracji jest podnoszona, z drugiej strony cesja nie jest.

Więc, kiedy po raz pierwszy wywołałeś console.log(value), odnosiłeś się do lokalnie zadeklarowanej zmiennej, która nie ma jeszcze nic przypisanego do niej; stąd undefined.

Oto inny przykład :

var test = 'start';

function end() {
    test = 'end';
    var test = 'local';
}

end();
alert(test);
Jak myślisz, co to zaalarmuje? Nie, Nie czytaj dalej, myśl o tym. Jaka jest wartość test? Jeśli powiedziałeś coś innego niż start, myliłeś się. Powyższy kod jest równoważny temu:
var test = 'start';

function end() {
    var test;
    test = 'end';
    test = 'local';
}

end();
alert(test);

Aby zmienna globalna nigdy nie została naruszona.

Jak widzisz, bez względu na to, gdzie umieścisz swoją deklarację zmiennej, jest ona zawsze podniesiona na górze twojego lokalnego zamknięcia.


Side Uwaga:

Dotyczy to również funkcji.

Rozważmy ten fragment kodu:

test("Won't work!");

test = function(text) { alert(text); }

Co da ci błąd odniesienia:

Uncaught ReferenceError: test nie jest zdefiniowany

To wyrzuca wielu programistów, ponieważ ten kawałek kodu działa dobrze:

test("Works!");

function test(text) { alert(text); }

Powodem tego, jak stwierdzono, jest to, że część przypisania jest , a nie podniesiona. Tak więc w pierwszym przykładzie, kiedy test("Won't work!") został uruchomiony, test zmienna została już zadeklarowana, ale nie ma jeszcze przypisanej funkcji.

W drugim przykładzie nie używamy przypisywania zmiennych. Zamiast tego używamy właściwej składni deklaracji funkcji, która sprawia, że funkcja jest całkowicie podniesiona.


Ben Cherry napisał doskonały artykuł na ten temat, odpowiednio zatytułowany JavaScript Scoping and Hoisting .
Przeczytaj. To da ci cały obraz w całości szczegóły.

 158
Author: Joseph Silber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-13 07:40:27

Byłem nieco rozczarowany, że problem tutaj został wyjaśniony, ale nikt nie zaproponował rozwiązania. Jeśli chcesz uzyskać dostęp do zmiennej globalnej w zakresie funkcji bez uprzedniego utworzenia niezdefiniowanego lokalnego var, odwołaj się do var jako window.varName

 43
Author: Amalgovinus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-22 20:18:13

Zmienne w JavaScript zawsze mają zakres funkcji. Nawet jeśli zostały zdefiniowane w środku funkcji, są widoczne wcześniej. Podobne zjawiska można zaobserwować przy podnoszeniu funkcji.

To powiedziawszy, pierwsza console.log(value) widzi zmienną value (wewnętrzną, która zacienia zewnętrzną value), ale nie została jeszcze zainicjowana. Można o tym myśleć tak, jakby wszystkie deklaracje zmiennych zostały pośrednio przeniesione na początek funkcji (, a nie w kodzie inner-most block), natomiast definicje są pozostawione w tym samym miejscu.

Zobacz też

 10
Author: Tomasz Nurkiewicz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:02:47

Istnieje zmienna globalna value, ale gdy kontrolka wchodzi w funkcję test, deklarowana jest inna zmienna value, która zacienia globalną. Ponieważ zmienne deklaracje (, ale nie przydziały) w JavaScript są podnoszone do góry zakresu, w którym są deklarowane:

//value == undefined (global)
var value = 10;
//value == 10 (global)

function test() {
    //value == undefined (local)
    var value = 20;
    //value == 20 (local)
}
//value == 10 (global)

Zauważ, że to samo dotyczy deklaracji funkcji, co oznacza, że możesz wywołać funkcję, zanim pojawi się ona zdefiniowana w Twoim kodzie:

test(); //Call the function before it appears in the source
function test() {
    //Do stuff
}

Warto również zauważyć, że gdy połącz te dwa wyrażenia w wyrażenie funkcji, zmienna będzie undefined dopóki nie nastąpi przypisanie, więc nie możesz wywołać funkcji, dopóki tak się nie stanie:

var test = function() {
    //Do stuff
};
test(); //Have to call the function after the assignment
 3
Author: James Allardice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-31 19:47:05