2016-01-22 2 views
4

У меня есть привычка, что я навязчиваюсь на грани, но я думаю, что это может быть совершенно ненужным. С такой код:Объявление переменной Javascript в цикле

function abc(){ 
    var a,b; 
    for(var i=0;i<10;i++){ 
    a=document.getElementsByTagName('LI').item(i).width; 
    b=document.getElementsByTagName('DIV').item(i).width; 
    // now do something with a and b 
    } 
    return; 
} 

Я компульсивное об объявлении переменной перед циклом, в отличие от:

function abc(){ 
    for(var i=0;i<10;i++){ 
    var a=document.getElementsByTagName('LI').item(i).width; 
    var b=document.getElementsByTagName('DIV').item(i).width; 
    // now do something with a and b 
    } 
    return; 
} 

Обратите внимание, что во втором блоке кода, я определяю переменную с var каждый раз, когда петля итерация. Я предполагаю, что первая - лучшая практика для удобочитаемости и т. Д. Но иногда я просто взламываю что-то и не нуждаюсь в лучшей практике.

Мой вопрос:

Есть ли какой-либо причине не определить переменную, которая будет получать переопределен с помощью ключевого слова var внутри цикла?

+3

В любом случае 'var' будет поднят, в том числе и в '' for''. IMO * not *, объявляющий их в верхней части функции (включая ту, что у вас нет), несет * импликацию *, что подъем не существует, а просто заставляет думать об этом сложнее, особенно когда будущий читатель может не полностью grok JS. И это просто шум. –

+0

Единственный раз, когда вам нужно использовать VAR, когда переменная будет находиться за пределами (глобальная). Выполнение этого внутри функции означает, что вы VAR это или нет, оно падает, когда функция выполняется в любом случае. Неважно, если вы делаете это внутри цикла или нет. Это потому, что внутри функции это бесполезно. – durbnpoisn

+0

@ durbnpoisn. Хм - может быть, я вас не понимаю, но это кажется противоположным моему пониманию. Если я не использую ключевое слово 'var' для определения переменной внутри функции, она будет втянута в глобальную область действия и, таким образом, создаст другие проблемы, не связанные с этим вопросом. – user1167442

ответ

10

Из-за переменной подъемки в Javascript нет технических различий в исполнении между var, находящимся в верхней части функции или внутри цикла for. Если это все, о чем вы заботитесь, тогда вы можете сделать это в любом случае.

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

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

В целом, рекомендуется только поставить код внутри цикла, который фактически должен находиться внутри цикла. Хотя это фактически ничего не меняет в выполнении, является ли var внутри или вне цикла, это просто часть хорошей практики, тогда как другой код внутри или вне цикла может иметь значение.

В вашем случае, я думаю, это было бы лучше практика:

function abc(){ 
    var liTags = document.getElementsByTagName('LI'); 
    var divTags = document.getElementsByTagName('DIV'); 
    var len = Math.min(liTags.length, divTags.length); 
    var a,b; 

    for(var i = 0; i < len; i++){ 
    a = liTags[i].width; 
    b = divTags[i].width; 

    // now do something with a and b 

    } 

    return; 
} 

Здесь вы удалили два вызов document.getElementsByTagName() из цикла, который сделает разницу ОГРОМНОЙ производительности.


Обновление в 2017. Javascript версии ES6, теперь поддерживает const и let для объявления переменных. Они ограничены областью, а не областью действия, например var, поэтому, если вы объявите один из них в блоке цикла for, тогда будет создана новая и отдельная переменная, созданная для каждого вызова цикла for.Хотя это не приведет к существенной разнице в исполнении кода, который вы показали, это может иметь значение, если в цикле был асинхронный код, который ссылается на переменную, которую вы объявляете. В случае const или let, используемых в теле цикла, каждый асинхронный вызов получит свою собственную отдельную копию переменной, которая иногда может быть очень удобной.

for(var i = 0; i < len; i++){ 
     let a = liTags[i].width; 
     let b = divTags[i].width; 

     $.get(someUrl).then(function(data) { 
      // each call to $.get() here in the loop has it's own a and b 
      // variables to use here, which would not be the case with var 
     }); 

    } 
+0

Первая часть вашего ответа ответила на мой вопрос первоначальный вопрос, думаю. Вы говорите чисто косметический? (Не то, что косметика неважна, но не критична при работе в консоли). Но вторая часть вашего вопроса подняла для меня еще один вопрос. Все ли поиск DOM происходит, когда 'liTags' захватывает все элементы' LI'? Если это так, итерация не будет отличаться от итерации по любому другому объекту *, подобному массиву *? См. Также мой комментарий к ответу @bultack. – user1167442

+2

@ user1167442 - 'getElementsByTagName()' возвращает *** live HTMLCollection ***. Это означает, что все элементы, которые он находит, есть изначально, но если DOM изменяется во время использования структуры данных, результаты будут обновляться в реальном времени. Это может быть благословение и проклятие (чаще всего это проклятие, на мой взгляд), и вам нужно следить за тем, обрабатываете ли вы HTMLCollection при изменении DOM таким образом, чтобы это повлияло на сам HTMLCollection. Иногда бывает целесообразно скопировать HTMLCollection в статический массив, чтобы предотвратить его изменение. – jfriend00

+0

Спасибо. Это очень полезно для использования в будущем. – user1167442

2

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

function abc() { 

    var a = document.getElementsByTagName('LI'), 
     b = document.getElementsByTagName('DIV'); 

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

    a.item(i).width; 
    b.item(i).width; 
    // now do something with a and b 

    } 

    return; 

} 
+0

Вы, похоже, пропустили, что в задании есть 'i', поэтому задание НЕОБХОДИМО находиться внутри цикла' for'. – jfriend00

+0

@ jfriend00. Вы правы. Хотя мой код псевдокод - его ответ будет порождать ошибки и не работать. – user1167442

+0

@ jfriend00 Теперь исправлено;) – abaracedo

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