Как работают переменные JavaScript? - PullRequest
13 голосов
/ 27 октября 2011

Я знаю, что переменные JavaScript указывают на значение:

var foo = true;
//... later 
foo = false;

Так что в этом примере я изменил foo, указывая на true -> foo, указывая на false, ноесли я сделаю:

for (var i=0; i<100; i++){
    var someVar = i;
}

Создаю ли я новую переменную для каждой итерации?

Есть ли разница в следующих двух способах сделать то же самое?

var myvar;
for (var i=0; i<100; i++){
    myvar = i;
}

и

for (var i=0; i<100; i++){
    var myvar = i;
}

Если так, то почему?

Ответы [ 5 ]

15 голосов
/ 27 октября 2011

В Javascript ES5 и более ранних версиях отсутствует область блока, только область действия функции.Более того, объявления всех переменных javascript, объявленных в области видимости функции, автоматически "поднимаются" в начало функции.

Таким образом, объявление переменной внутри цикла ничего не делаетотличается от объявления его в верхней части функции и последующего обращения к нему внутри цикла.

См. эти две ссылки для некоторых полезных объяснений: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting и http://net.tutsplus.com/tutorials/javascript-ajax/quick-tip-javascript-hoisting-explained/.

Примечание: присваивание переменной не выполняется, только объявление переменной.Итак, если вы сделаете это:

function a() {
    for (var i=0; i<100; i++){
        var myvar = i;
    }
}

Это работает так:

function a() {
    var myvar;
    for (var i=0; i<100; i++){
        myvar = i;
    }
}

Если вы хотите создать новую область в цикле for, вы можете использовать IIFE(немедленно вызывается выражение функции), например:

function a() {
    for (var i=0; i<100; i++){
        (function() {
            var myvar = i;
            // myvar is now a separate variable for each time through the for loop
        })();
    }
}

Обновление в 2015 году. ES6 (или иногда называемый ES2015) предлагает объявление let, которое предлагает область действия блока.В этом случае объявление переменной let поднимается только до верхней части текущей области блока.По состоянию на середину 2015 года это еще не получило широкого распространения в браузерах, но скоро будет доступно и доступно в серверных средах, таких как node.js или через транспортеры.

Итак, в ES6, если вы сделали это:

for (let i=0; i<100; i++){
    let someVar = i;
}

И i, и someVar будут локальными только для цикла.

13 голосов
/ 27 октября 2011

Нет, разницы нет; в JavaScript переменные находятся на уровне функций, а не на уровне блоков.

2 голосов
/ 27 октября 2011

Инструменты типа JSLint рекомендуют помещать все ваши операторы var в начале функций.Это потому, что JavaScript, по сути, делает это за вас, если вы этого не сделаете, поэтому это менее запутанно, если вы делаете.В вашем примере не имеет значения, куда вы положили var, если это происходит до одного определения myvar.Кроме того, вы также можете объявить i в верхней части функции.

Что более интересно, так это иерархическая цепочка областей действия , в которой JavaScript ищет имена, когда хочет посмотретьодин вверх.Он ищет цепочку областей действия от local до global , пока не найдет первый экземпляр указанного имени.

Именно поэтому вы можете играть в такие игры, чтобы раздражать своихдрузья:

function foofinder() {
    var bar = function () { return foo; },
        foo="beers";
    return bar();
}

foofinder();
>>> "beers"
2 голосов
/ 27 октября 2011

Как сказал @icktoofay, в javascript нет никакой разницы. В некоторых языках на каждой итерации переменная будет создаваться, затем выходить из области видимости и оставляться для сборки мусора.

Чтобы смоделировать это в javascript, вы можете сделать:

for (var i=0; i<100; i++){
    (function(){
        var myvar = i;
    })();
}

В этом случае myvar существует только в области действия анонимной функции, поэтому на каждой итерации создается новый экземпляр myvar.

0 голосов
/ 27 октября 2011

Постоянно объявляя var перед именем переменной, вы могли бы дать указание механизму JavaScript или интерпретатору повторно инициализировать переменную с неопределенным значением (undefined в отличие от числа, строки / текста, логического значения,или null) перед присваиванием, что было бы дополнительными инструкциями, замедляющими скорость выполнения цикла.Вы также увеличиваете размер кода и снижаете скорость, с которой код анализируется / интерпретируется / компилируется.

Практически для любого приложения функциональной разницы нет, но она есть, и разница может быть заметнойпосле сотен тысяч или миллиардов выполнений цикла.Однако повторные объявления VAR с одним и тем же именем внутри функции приводят к фатальным исключениям в Chrome / V8.

ОБНОВЛЕНИЕ: Использование var перед тем, как имя переменной значительно медленнее , чем опущение var, как показано в следующем тесте, запущенном на Chrome / v8 с консолью JavaScript.

var startTime = new Date().getTime();
var myvar;
for (var i=0; i<100000; i++){
    myvar = i;
}
console.log(new Date().getTime() - startTime);

var startTimx = new Date().getTime();
var myvax;
for (var j=0; j<100000; j++){
var myvax = j;
}
console.log(new Date().getTime() - startTimx);
161
169

Первый тест, выполненный за 161 мс, и второй тест (с var) потребовалось 169 мс для выполнения.Разница составляет 7 мс, что соответствует разным прогонам теста.

Весь тест был вставлен в консоль Chrome JavaScript, а затем скомпилирован перед его выполнением, поэтому первый вывод не отображается ниже первоговызовите console.log ().

Попробуйте сами!

...