2010-09-10 4 views
180

В AS3 я считаю, что вы должны инициализировать все переменные за пределами циклов для повышения производительности. Так ли это с JavaScript? Что лучше/быстрее/лучше?Переменные 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]; 
} 
+7

Снаружи! всегда снаружи. – BGerrissen

+29

Хм, не объявляются ли переменные объявления в любом случае как в Javascript, так и в AS3? Если я прав, то это действительно не имеет значения. – spender

+3

@ Энди - вы пытались назначить перед объявлением в теле функции? Возможно, ваши предубеждения ведут вас в заблуждение. Производительность WRT, с учетом масштабирования, если JS интерпретируется, то он будет переваривать дополнительные циклы в блоке цикла. Если скомпилировано (что большинство двигателей делает сейчас), это не имеет значения. – spender

ответ

241

Существует абсолютно без разницы в смысле или исполнении, в 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; 

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

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

(*: кроме как в вложенной функции органов)

+4

Я все еще не могу решить, имею ли я с Крокфордом или нет на этом. Объявление переменных внутри блоков немного напоминает использование операторов условных функций (что непослушно) ... Однако я согласен с вашими точками :) #confused –

+18

+1 Я не согласен с рассуждениями Крокфорда (цитируется в ответе Даниэля), как JavaScript разработчикам мы не должны писать код, чтобы другие программисты C-семейства могли его понять. Я часто использую * var * внутри * if * блоков и циклов, потому что это имеет больше смысла для меня. –

+4

-1 ОП задает вопрос о том, должны ли объявляться вары в теле цикла до начала цикла. Значение индекса цикла явно является особым случаем (и поднимается) и вообще не помогает OP. – mkoistinen

60

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

Я не уверен в аргументе производительности, но Douglas Crockford по-прежнему рекомендует, чтобы операторы var были первыми утверждениями в теле функции. Цитата из Code Conventions for the JavaScript Programming Language:

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

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

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

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

+1 для того, чтобы сообщать OP-истины о сфере действия JS. Я задаюсь вопросом, следует ли использовать ответы, которые говорят иначе? – spender

+1

@Kieranmaine: Я не сказал, что это не влияет на производительность. Я просто сделал аргумент для того, чтобы поместить их за пределы циклов, не относящихся к производительности ... У меня нет ссылок на аргументы производительности, но вы не указали ни одного в своем ответе :) –

+1

@Kieranmaine: вы есть источник для этого? –

0

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

+0

Я обнаружил, что нажатие всех объявлений переменных в верхнюю часть, включая временные переменные, может привести к путанице, поскольку она просто «шумно». –

10

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

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

55

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 вы можете получить доступ к этой переменной в любом месте текущей области.

+2

+1 информативный! – mkoistinen

+0

Тот же базовый ответ, что и принятый, но ИМО, более читаемый и примерно такой же информативный. Хорошая работа. –

+1

Как «пусть» ES6 влияет на этот ответ? – jbyrd

4

Я просто сделал простой тест в 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-й тест, где я предварительно объявляю индекс.

+0

+1 для доказанных результатов. –

+0

Я попробовал ваш тестовый пример с 10 миллионами итераций вместо 100 миллионов. Chrome 6.0.472 для Mac (2,93 ГГц Intel Core 2 Duo - 6 ГБ оперативной памяти): http://img691.imageshack.us/img691/3581/chrometest.jpg ... Не вижу различий. –

+11

@KP: результаты доказаны, только если вы их сами тестируете или если их проверяет большое количество людей. @mkoistinen: Я построил более справедливое испытание, http://jsfiddle.net/GM8nk/. После запуска сценария несколько раз в Chrome 5, я мог видеть, что не было последовательного победителя. Все три вариации выполнялись лучше, чем другие после нескольких обновлений. Я, боюсь, от меня. Обратите внимание, что вы можете запустить [этот] (http://jsfiddle.net/GM8nk/1/) в других браузерах. IE и Fx не понравились 100 миллионов итераций. –

1

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

+0

C или C++ могут быть внизу JavaScript. Но мы не должны забывать, что браузер преобразует JavaScript в базовый язык (C, C++). Таким образом, производительность зависит от браузера – Kira

+1

@Kira. На самом деле он не преобразуется в C/C++. Javascript скомпилирован в набор инструкций, выполняемых средой исполнения JS (то есть виртуальной машиной, запущенной в браузере). Тот же принцип применяется к другим динамическим языкам, таким как Python и Ruby. –

+0

@ Энтони, спасибо за информацию. Я не был уверен в преобразовании JS на C или C++. Таким образом, я использовал * может быть * в моем комментарии – Kira

-1

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

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

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

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

2

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

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

В отношении производительности после запуска тест на 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' находятся в строке объявления цикла цикла. Эта встроенная декларация обеспечила мне стабильно лучшую производительность. Даже над объявлением переменных вне цикла. Опять же разница в производительности очень мала.

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

+0

Для меня ваш тест дал внутри цикла. И, тем не менее, это не так, разница слишком мала, чтобы заключить, и принятый ответ четко объясняет ** нет никакой разницы ** –

+0

Поскольку объявления переменных поднимаются, на самом деле нет никакой разницы. – trincot

Смежные вопросы