Подтвердить что ты не робот

Как работают переменные JavaScript?

Я знаю, что JavaScript-символы указывают на значение:

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

Итак, в этом примере я изменил foo на truefoo, указав на false, но если:

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

Я создаю новый var для каждой итерации?

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

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

и

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

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

4b9b3361

Ответ 1

В области 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 или через transpilers.

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

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

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

Ответ 2

Нет, нет разницы; в JavaScript переменные ограничены уровнем функции, а не уровнем блока.

Ответ 3

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

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

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

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

Ответ 4

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

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

Вот почему вы можете играть в подобные игры, чтобы раздражать своих друзей:

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

foofinder();
>>> "beers"

Ответ 5

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

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

UPDATE: Использование 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().

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