Переменные JavaScript объявляют внешний или внутренний цикл?

В AS3 я считаю, что вы должны инициализировать все переменные за пределами циклов для повышения производительности. Так ли это с JavaScript? Что лучше/быстрее/лучше всего?

var value = 0;

for (var i = 0; i < 100; i++)
{
    value = somearray[i];
}

или

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}

Ответ 1

не имеет значения по смыслу или производительности в JavaScript или ActionScript.

var - это директива для синтаксического анализатора, а не команда, выполняемая во время выполнения. Если конкретный идентификатор был объявлен var один или несколько раз в любом месте тела функции (*), то все использование этого идентификатора в блоке будет ссылаться на локальную переменную. Не имеет значения, объявлен ли value var внутри цикла, вне цикла или для обоих.

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

В частности:

for (var i; i<100; i++)
    do something;

for (var i; i<100; i++)
    do something else;

Crockford рекомендует вам удалить второй var (или удалить оба var и сделать var i; выше), и jslint будет зависеть от вас для этого. Но IMO более сдержанно поддерживать оба var s, сохраняя вместе все связанный код, вместо того, чтобы иметь лишний, легко забытый бит кода в верхней части функции.

Лично я склонен объявлять как var первое присваивание переменной в независимом разделе кода, независимо от того, существует ли другое отдельное использование одного и того же имени переменной в некоторой другой части той же функции. Для меня обязательным объявлением var является нежелательная бородавка JS (было бы лучше иметь переменные по умолчанию для локальных); Я не считаю своим долгом дублировать ограничения [старой ревизии] ANSI C в JavaScript.

(*: кроме вложенных тел функции)

Ответ 2

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

Я не уверен в аргументе производительности, но Дуглас Крокфорд по-прежнему рекомендует, чтобы операторы var должны были быть первыми утверждениями в функция корпус. Вывод из Кодовые обозначения для языка программирования JavaScript:

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

Я думаю, что у него есть точка, как вы можете видеть в следующем примере. Объявление переменных в верхней части функции не должно путать читателей с мыслью, что переменная i сохраняется в области цикла for:

function myFunction() {
  var i;    // the scope of the variables is very clear

  for (i = 0; i < 10; i++) {
    // ...
  }
}

Ответ 3

Язык ECMA-/Javascript hoists любая переменная, которая объявляется в любом месте в верхней части функции. Это потому, что на этом языке есть function scope и не имеет block scope, как и многие другие C-подобные языки. Это также известно как lexical scope.

Если вы объявите что-то вроде

var foo = function(){
    for(var i = 0; i < 10; i++){
    }
};

Это получает hoisted:

var foo = function(){
    var i;
    for(i = 0; i < 10; i++){
    }
}

Таким образом, это не влияет на производительность (но поправьте меня, если я здесь совершенно не прав).
Гораздо лучший аргумент для не, объявляющий переменную где-то еще, чем в верхней части функции, - это удобочитаемость. Объявление переменной внутри for-loop может привести к ошибочному предположению, что к этой переменной можно получить доступ только в теле цикла, которое полностью неверно. Infact вы можете получить доступ к этой переменной в любом месте текущей области.

Ответ 4

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

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

Ответ 5

Я просто сделал простой тест в Chrome. Попробуйте fiddle в своем браузере и посмотрите результаты

  var count = 100000000;
    var a = 0;
    console.log(new Date());

    for (var i=0; i<count; i++) {
      a = a + 1
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
      a = a + 1;
    }

    console.log(new Date());

    var j;
    for (j=0; j<count; j++) {
        var x;
        x = x + 1;
    }

    console.log(new Date());

Результат состоит в том, что последний тест занимает ~ 8 секунд, а предыдущие 2 - всего ~ 2 секунды. Очень повторяемо и независимо от порядка.

Итак, это доказывает мне, что всегда нужно объявлять вары вне цикла. Любопытный случай для меня - это первый, где я объявляю i в инструкции for(). Кажется, что это так же быстро, как и 2-й тест, где я предварительно объявляю индекс.

Ответ 6

Еще одно соображение, теперь, когда мы имеем let и const в ES2015, заключается в том, что теперь вы можете теперь использовать переменные области видимости для блока цикла. Поэтому, если вам не понадобится одна и та же переменная вне цикла (или если каждая итерация зависит от операции, выполняемой с этой переменной в предыдущей итерации), вероятно, предпочтительнее сделать это:

for (let i = 0; i < 100; i++) {
    let value = somearray[i];
    //do something with `value`
}

Ответ 7

JavaScript - это язык, написанный внизу C или С++, я не очень уверен, какой он. И одна из его целей заключается в сохранении возможности обработки внутренней памяти. Даже в C или С++ вам не придется беспокоиться о том, будет ли он потреблять много ресурсов, когда переменные объявляются внутри цикла. Почему вы должны беспокоиться об этом в JavaScript?

Ответ 8

Ну, это зависит от того, чего вы пытаетесь достичь... если value предположим, что это только временная переменная внутри цикла цикла, то гораздо более яснее использовать вторую форму. Это также более логично и многословно.

Ответ 9

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

var a = 30;
var a = 50;
var a = 60;

Считаете ли вы, что это правильно? Нет... потому что вы не хотите объявлять переменную столько раз. Когда вы объявляете переменную внутри цикла, не объявляете ли она столько раз, сколько цикл работает? Очевидно, что это ударит вас, когда вы находитесь в режиме "строгого режима". Люди не согласны с Крокфордом, не задумываясь о первоначальном вопросе.

Так что всегда полезно объявлять переменные сверху - 1. Для читаемости, 2. Хорошие привычки.

Ответ 10

Что касается производительности после запуска теста на Chrome, Firefox и jsperf в ОС Linux, то существует разница в производительности между объявлением переменных в цикле и из цикла. Это небольшая разница, но это также усугубляется количеством итераций и количеством объявлений переменных.

Поэтому для лучшей производительности я должен был бы предложить объявить переменные за пределами цикла. Или еще лучше объявить переменные в строке. См. Пример.

// inline
for (var ai = 0, al = 100000000, av; ai < al; ai++) {
    av = av + 1;
}

// outside
var bv;
var bl = 100000000;
for (var bi = 0; bi < bl; bi++) {
    bv = bv + 1;
}

Обратите внимание, как переменная 'al' и 'av' находятся в строке объявления цикла for. Эта встроенная декларация обеспечила мне стабильно лучшую производительность. Даже над объявлением переменных вне цикла. Опять же разница в производительности очень мала.

https://jsperf.com/outside-inline-for-loop-ase/1