Удивлена, что глобальная переменная имеет значение undefined в JavaScript

Сегодня я был полностью удивлен, когда увидел, что глобальная переменная имеет значение undefined в определенном случае.

Пример:

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

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

Дает вывод как

undefined
20

Вот почему механизм JavaScript рассматривает глобальное значение как undefined. Я знаю, что JavaScript является интерпретированным языком. Как он может рассматривать переменные в функции?

Является ли это ошибкой от механизма JavaScript?

Ответ 1

Это явление известно как: Перемещение JavaScript Variable.

Ни в коем случае вы не обращаетесь к глобальной переменной в своей функции; вы всегда получаете доступ к локальной переменной value.

Ваш код эквивалентен следующему:

var value = 10;

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

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

test();

Вы все еще удивляетесь, что получаете undefined?


Объяснение:

Это то, что каждый программист JavaScript рано или поздно сталкивается. Проще говоря, любые переменные, которые вы объявляете, всегда поднимаются вверху вашего локального закрытия. Таким образом, даже если вы объявили свою переменную после первого вызова console.log, она по-прежнему считается так, как если бы вы объявили ее до этого.
Однако поднимается только часть декларации; с другой стороны, назначение не является.

Итак, когда вы впервые вызвали console.log(value), вы ссылались на свою локально объявленную переменную, которая пока ничего не назначила; следовательно, undefined.

Здесь еще один пример:

var test = 'start';

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

end();
alert(test);

Как вы думаете, что это будет предупреждать? Нет, не просто читайте, подумайте об этом. Какое значение test?

Если вы сказали что-то кроме start, вы ошибались. Вышеприведенный код эквивалентен этому:

var test = 'start';

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

end();
alert(test);

чтобы глобальная переменная никогда не затрагивалась.

Как вы можете видеть, независимо от того, где вы помещаете объявление переменной, оно всегда поднимается вверху вашего локального закрытия.


Боковое примечание:

Это также относится к функциям.

Рассмотрим этот фрагмент кода:

test("Won't work!");

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

который даст вам опорную ошибку:

Неподготовлено ReferenceError: тест не определен

Это отбрасывает множество разработчиков, так как этот фрагмент кода работает отлично:

test("Works!");

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

Причиной этого, как указано, является то, что часть назначения не поднята. Итак, в первом примере, когда был запущен test("Won't work!"), переменная test уже объявлена, но еще не назначена ей функция.

Во втором примере мы не используем назначение переменной. Скорее, мы используем правильный синтаксис объявления функции, который полностью выполняет функцию.


Ben Cherry написал прекрасную статью об этом, соответственно названную JavaScript Обзор и подхват.
Прочтите. Это даст вам полную картину в полной мере.

Ответ 2

Я был несколько разочарован тем, что проблема здесь объясняется, но никто не предложил решение. Если вы хотите получить доступ к глобальной переменной в области функций без функции, создающей локальный var undefined, сначала укажите var как window.varName

Ответ 3

Переменные в JavaScript всегда имеют функциональную область. Даже если они были определены в середине функции, они видны раньше. Аналогичные явления могут наблюдаться при подъеме функции.

При этом первая console.log(value) видит переменную value (внутреннюю, которая скрывает внешний value), но она еще не была инициализирована. Вы можете думать об этом так, как будто все объявления переменных неявно перемещаются в начало функции (не внутренний код кода), а определения остаются на одном месте.

См. также

Ответ 4

Существует глобальная переменная value, но когда элемент управления входит в функцию test, объявляется другая переменная value, которая затеняет глобальную. Поскольку объявления переменных (но не присваивания) в JavaScript поднимаются в начало области, в которой они объявлены:

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

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

Обратите внимание, что то же самое относится к объявлениям функций, что означает, что вы можете вызвать функцию до того, как она будет определена в вашем коде:

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

Также стоит отметить, что при объединении двух в выражение функции переменная будет undefined до тех пор, пока не произойдет присвоение, поэтому вы не сможете вызвать функцию до тех пор, пока это не произойдет:

var test = function() {
    //Do stuff
};
test(); //Have to call the function after the assignment