JavaScript Лексическая область видимости и переменная жизнь - PullRequest
1 голос
/ 15 ноября 2011

Мне было любопытно, почему это работает:

function doThis(){
    counter = 0;
    return counter;
};

console.log(counter); // returns "reference error: can't find variable"

, что имеет смысл, поскольку переменная не существует вне функции. Но если я сделаю функцию, которая выполняется самостоятельно:

(function doThis(){
    counter = 0;
    return counter;
})();

console.log(counter); // returns 0

Почему переменная counter все еще существует? Это не закрытие, нет ничего, что, кажется, ссылается на эту переменную извне, так что не должно ли это быть уничтожено сборкой мусора?

Ответы [ 5 ]

6 голосов
/ 15 ноября 2011

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

Функция в первом примере не была вызвана, поэтому переменная еще не была создана, а во втором - так, поэтому вы получаете 0

Что должен делать ваш код:

function doThis(){
    var counter = 0;
    return counter;
};
4 голосов
/ 15 ноября 2011

Сначала отредактируйте их так, чтобы сразу было понятно, что происходит (не пропуская var hacks):

function doThis(){
    window.counter = 0;
    return counter;
};

console.log(window.counter); // returns undefind

И

(function doThis(){
    window.counter = 0;
    return counter;
})();

console.log(window.counter); // returns 0

Теперь вы видите, что происходит? Функция определяет глобальную переменную, поэтому, конечно, она недоступна, пока не будет вызвана функция. window относится к [object global] в браузерах.

По этой причине вы всегда хотите использовать либо global.something ИЛИ var something, чтобы всем было ясно, собираетесь ли вы использовать глобальную или локальную переменную. Если вы используете var в OP, переменная будет локальной.

3 голосов
/ 15 ноября 2011

Так как вы не объявляете его с помощью «var», оно присваивается глобальной области видимости, которая видна за пределами функции. В первом примере вы не выполняете функцию, поэтому счетчик никогда не определяется, где, как и во втором примере, вы вызываете функцию, и счетчик присваивается глобальной области действия

2 голосов
/ 15 ноября 2011

В первом примере вы еще не вызывали функцию, поэтому counter еще не существует (потому что код внутри функции еще не выполнен). Во втором примере вы определили литерал функции и вызываете его самостоятельно. Код внутри функции execute и counter теперь определен.

Более того, counter - это глобальная переменная, потому что вы не определили ее с помощью var, и поэтому она видна области видимости за пределами функции. Это то же самое, что и window.counter = 0.

Теперь, если вы сделали следующее:

(function doThis(){
    var counter = 0; //notice the var
    return counter;
})();

counter по-прежнему будет неопределенным, поскольку он является локальным для области действия функции.

Итак, резюмируем:

  • В первом примере counter не определено, поскольку код еще не запущен. Если вы действительно вызовете функцию, вы получите то же поведение, что и во втором примере.
  • Во втором примере counter определено и является глобальной переменной (в основном такой же, как window.counter), и это определяется потому, что код внутри функции был выполнен, когда вы определили ее и вызвали самостоятельно. *
  • В третьем примере counter неизвестно глобальной области видимости, потому что оно является локальным для функции, внутри которой оно было определено (поскольку использовалось var).
0 голосов
/ 01 февраля 2017

Как вы знаете, в JavaScript, если вы объявите переменную без ключевого слова "var", она будет добавлена ​​в глобальную область (объект окна).

Но если переменная объявлена ​​внутри функции без использования ключевого слова «var», она не будет добавлена ​​в глобальную область (объект окна), пока эта конкретная функция не будет вызвана. В JavaScript вы должны понимать, как создавать контекст выполнения.

когда интерпретируется полный файл JS, память выделяется для всех функций и переменных (подъем). Обратите внимание, что все переменные, которые объявлены вне функций, добавляются в глобальную область (объект окна).

Фаза исполнения:

Поскольку выполнение кода JS является синхронным (только одна строка за раз) и однопоточным, создается стек выполнения, а «глобальный контекст выполнения» помещается в стек выполнения. Если при выполнении встречается вызов функции, для соответствующей функции создается «контекст выполнения функции» и помещается в тот же стек.

Теперь во время выполнения функции движок JS анализирует код и, если он встречает переменную, выделяется память, и если переменная объявляется без ключевого слова «var», она добавляет эту конкретную переменную в глобальную область. в противном случае эта конкретная переменная будет частью области действия функции (локальной области видимости).

Теперь давайте проверим ваши фрагменты кода:

function doThis(){
    counter = 0;
    return counter;
};

console.log (счетчик); // возвращает "ошибка ссылки: не удается найти переменную"

в этом примере, так как функция doThis () никогда не выполняется, переменная «counter» не выделяется никакой памяти и не является частью какой-либо области (глобальной / локальной). следовательно, в журнале консоли вы видите ошибку ссылки.

(function doThis(){
    counter = 0;
    return counter;
})();

console.log (счетчик); // возвращает 0

В качестве самопризываемой функции переменная «counter» будет выделена память и перемещена в глобальную область видимости (объект окна). следовательно, вы можете увидеть значение переменной «counter» в журнале консоли.

...