Variáveis ​​JavaScript declaram loop externo ou interno?

212

No AS3, acredito que você deve inicializar todas as variáveis ​​fora dos loops para aumentar o desempenho. Este também é o caso do JavaScript? Qual é a melhor / mais rápida / melhor prática?

var value = 0;

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

ou

for (var i = 0 ; i < 100; i++)
{
    var value = somearray[i];
}
davivid
fonte
7
Lado de fora! sempre lá fora.
BGerrissen
37
Hmm, as declarações de variáveis ​​não são empurradas para o escopo da função de qualquer maneira, tanto em Javascript quanto em AS3? Se estou certo, isso realmente não importa.
spender
3
@ Andy - você tentou atribuir antes de declarar em um corpo de função? Talvez seus preconceitos estejam levando você a se desviar. O desempenho do WRT, com escopo de flexão, se o JS for interpretado, ele produzirá ciclos extras dentro de um bloco de loop. Se compilado (o que a maioria dos mecanismos faz hoje em dia), não importa.
spender
2
Ótima pergunta! Obrigado. Depois de ler todas as respostas, acredito que se for apenas um pequeno loop ou apenas uma variável temporária, vou mantê-las onde são necessárias e isso não afeta o desempenho. Se um var é utilizado dentro de uma função mais do que uma vez, por isso não se referem a ele dentro da função e, finalmente, em seguida, pode ser globais sentou-se fora o fn ()
Dean Meehan
3
Estou surpreso que ninguém tenha tentado medir o desempenho. Eu criei um jsperf . Parece ser um pouco mais rápido quando declarados dentro do loop para o Safari e Firefox, o oposto para o Chrome ...
Buzut

Respostas:

281

Não há absolutamente nenhuma diferença em significado ou desempenho, em JavaScript ou ActionScript.

varé uma diretiva para o analisador e não um comando executado em tempo de execução. Se um identificador específico tiver sido declarado varuma ou mais vezes em qualquer lugar do corpo da função (*), todo o uso desse identificador no bloco estará se referindo à variável local. Não faz diferença se valueé declarado vardentro do loop, fora do loop ou em ambos.

Consequentemente, você deve escrever o que achar mais legível. Discordo de Crockford de que colocar todos os vars no topo de uma função é sempre a melhor coisa. No caso em que uma variável é usada temporariamente em uma seção do código, é melhor declarar varnessa seção, para que a seção fique sozinha e possa ser copiada e colada. Caso contrário, copie e cole algumas linhas de código em uma nova função durante a refatoração, sem selecionar e mover separadamente o associado var, e você terá um mundo acidental.

Em particular:

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

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

Crockford recomendará que você remova o segundo var(ou remova ambosvar e faça var i;acima), e o jslint o fará querer isso. Mas, na IMO, é mais sustentável manter os dois vars, mantendo todo o código relacionado unido, em vez de ter um trecho extra de código facilmente esquecido na parte superior da função.

Pessoalmente, tenho a tendência de declarar var a primeira atribuição de uma variável em uma seção independente de código, se existe ou não outro uso separado do mesmo nome de variável em alguma outra parte da mesma função. Para mim, ter que declarar varé uma verruga JS indesejável (seria melhor ter variáveis ​​padrão para local); Não vejo como meu dever duplicar as limitações de [uma antiga revisão do] ANSI C em JavaScript também.

(*: exceto em corpos de função aninhados)

bobince
fonte
4
Ainda não consigo decidir se estou com Crockford ou não neste. Declarar variáveis dentro de blocos sente um pouco como o uso de declarações de função condicional (que é impertinente) ... No entanto, concordo com os seus pontos bem :) #confused
Daniel Vassallo
20
+1 Discordo do raciocínio de Crockford (citado na resposta de Daniel), como desenvolvedores de JavaScript não devemos escrever código para que outros programadores da "família C" possam entendê-lo. Costumo usar var inside se blocos e loops, porque faz mais sentido para mim.
Andy E
4
-1 O OP está perguntando se os vars no corpo do loop devem ser declarados antes do início do loop. O valor do índice do loop é claramente um caso especial (e é içado) e não ajuda em nada o OP.
precisa saber é o seguinte
21
Os índices de loop não são um caso especial, são manipulados e içados exatamente da mesma maneira que uma atribuição normal.
22910
31
+1 Crockford está errado sobre este (e outros, mas discordo). Exigir que varseja usado apenas na parte superior de uma função é apenas solicitar a criação acidental de variáveis ​​globais. E ter uma massa de variáveis ​​não relacionadas todas declaradas em um ponto é semanticamente sem sentido, especialmente quando algumas dessas variáveis ​​podem acabar nunca sendo usadas.
MooGoo 10/09/10
64

Em teoria, não deve fazer diferença no JavaScript, pois a linguagem não possui escopo de bloco, mas apenas escopo de função.

Não tenho certeza sobre o argumento de desempenho, mas Douglas Crockford ainda recomenda que as varinstruções sejam as primeiras no corpo da função. Citando Convenções de Código para a Linguagem de Programação JavaScript :

O JavaScript não possui escopo de bloco, portanto, a definição de variáveis ​​em blocos pode confundir programadores experientes com outras linguagens da família C. Defina todas as variáveis ​​na parte superior da função.

Eu acho que ele tem razão, como você pode ver no exemplo a seguir. Declarar as variáveis ​​na parte superior da função não deve confundir os leitores ao pensarem que a variável i é mantida no escopo do forbloco de loop:

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

  for (i = 0; i < 10; i++) {
    // ...
  }
}
Daniel Vassallo
fonte
8
+1 por dizer as verdades do OP sobre o escopo do JS. Eu estou querendo saber se o voto será negativo ou não, que diga o contrário!
gastador
1
@Kieranmaine: Eu não disse que isso não afeta o desempenho. Acabei de argumentar para colocá-los fora dos loops, irrelevantes para o desempenho ... Eu não tenho nenhuma referência para os argumentos de desempenho, mas você também não citou nenhuma na sua resposta :)
Daniel Vassallo
1
@Kieranmaine: você tem uma fonte para isso?
Andy E
5
@ Kieranmaine: O AFAIK, mesmo que você declare variáveis ​​dentro de um loop, ecma- / javascriptaumentará essas em tempo de execução. Isso é chamado de "elevação". Portanto, não deve haver nenhuma diferença.
precisa saber é
1
Como o ES6 letafeta essa resposta?
jbyrd
58

O ECMA-/Javascriptidioma de hoistsqualquer variável declarada em qualquer lugar no topo de uma função. Isso é porque essa linguagem não tem function scopee faz não têm block scopecomo muitas outras linguagens C-like.
Isso também é conhecido como lexical scope.

Se você declarar algo como

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

Isso chega hoisteda:

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

Portanto, não faz nenhuma diferença no desempenho (mas me corrija se estiver totalmente errado aqui).
Um argumento muito melhor para não declarar uma variável em outro lugar do que na parte superior de uma função é a legibilidade . Declarar uma variável dentro de um for-looppode levar à suposição errada de que essa variável só pode ser acessada dentro do corpo do loop, o que está totalmente errado . De fato, você pode acessar essa variável em qualquer lugar do escopo atual.

jAndy
fonte
A mesma resposta básica que a aceita, mas, na OMI, mais legível e igualmente informativa. Bom trabalho.
Anne Gunn
5
Como o ES6 letafeta essa resposta?
jbyrd
13

No próximo ano, todos os navegadores terão mecanismos JS que pré-compilam o código, para que a diferença de desempenho (que vem da análise do mesmo bloco de código repetidamente e da execução da atribuição) se torne insignificante.

Além disso, nunca otimize o desempenho, a menos que seja necessário. Manter as variáveis ​​próximas ao local em que você precisa delas na primeira vez mantém seu código limpo. No lado negativo, as pessoas que estão acostumadas a idiomas com escopos de bloco podem ficar confusas.

Aaron Digulla
fonte
6

Outra consideração, agora que temos lete constno ES2015, é que agora você pode escopo variáveis ​​especificamente para o bloco de loop. Portanto, a menos que você precise da mesma variável fora do loop (ou se cada iteração depende de uma operação feita nessa variável na iteração anterior), provavelmente é preferível fazer isso:

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

Acabei de fazer um teste simples no Chrome. Experimente o violino no seu navegador e veja os resultados

  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());

O resultado é que o último teste leva ~ 8 segundos e os 2 anteriores são apenas ~ 2 segundos. Muito repetidamente e independentemente da ordem.

Então, isso prova para mim que sempre se deve declarar os vars fora do loop. Caso curioso para mim é o primeiro onde declaro ina declaração for (). Este parece ser tão rápido quanto o segundo teste em que eu pré-declaro o índice.

mkoistinen
fonte
14
@KP: os resultados são comprovados apenas se você os testar ou se um grande número de pessoas os verificar. @mkoistinen: Eu construí um teste mais justo, jsfiddle.net/GM8nk . Depois de executar o script várias vezes no Chrome 5, pude ver que não havia um vencedor consistente. Todas as três variações tiveram um desempenho melhor do que as outras após algumas atualizações. -1 de mim, eu tenho medo. Observe que você pode querer executá- lo em outros navegadores. O IE e o Fx não gostaram de 100 milhões de iterações.
Andy E
1
@AndyE. Uau, então, com base neste teste simples, o IE suga 100X mais? =)
mkoistinen
2
Os resultados estão em todo lugar para mim, nenhum vencedor claro entre navegadores, embora às vezes haja diferenças significativas de velocidade. Esquisito. Eu acho que o violino de Andy é um teste melhor, colocando cada candidato em sua própria função ... certamente, se o script original for executado fora de uma função, ele realmente não deveria estar testando nada, pois varestá declarando como global uma variável que seria seja global de qualquer maneira.
bobince
4
Mais de um ano após o fato, mas SHAPOW
sdleihssirhc 9/12/11
2
Isso não é meu, mas imaginei que alguns de vocês estariam interessados: jsperf.com/var-in-for-loop
m1.
1

JavaScript é uma linguagem escrita na parte inferior por C ou C ++, não tenho muita certeza de qual é. E um de seus objetivos é economizar o manuseio de lidar com a memória interna. Mesmo em C ou C ++, você não precisará se preocupar se consumirá muitos recursos quando variáveis ​​forem declaradas dentro de um loop. Por que você deveria se preocupar com isso em JavaScript?

Yan Yang
fonte
1
C ou C ++ pode estar na parte inferior do JavaScript. Mas não devemos esquecer que o navegador converte JavaScript para o idioma subjacente (C, C ++). Portanto, o desempenho depende do navegador
Kira
3
@Kira Na verdade, não é convertido em C / C ++. Javascript é compilado em um conjunto de instruções que são executadas pelo tempo de execução JS (ou seja, uma máquina virtual em execução no navegador). O mesmo princípio se aplica a outras linguagens dinâmicas, como Python e Ruby.
Anthony E
@ AnthonyE, Obrigado pela informação. Eu não tinha certeza sobre JS convertendo para C ou C ++. Então, eu usei pode estar no meu comentário
Kira
0

Bem, isso depende do que você está tentando alcançar ... se valuesuponha ser apenas uma variável temporária dentro do bloco de loop, é muito mais claro usar a segunda forma. Também é mais lógico e detalhado.

Crozin
fonte
Eu descobri que empurrar todas as declarações de variáveis ​​para o topo - incluindo variáveis ​​temporárias - pode realmente causar confusão, pois fica "barulhento".
Daniel Sokolowski
0

Não faz diferença se você declarar variáveis ​​dentro ou fora do loop for. Abaixo está o código de exemplo para testar.

function a() {
   console.log('Function a() starts');
   console.log(new Date());
    var j;
    for (j=0; j<100000000; j++) {
        var x;
        x = x + 1;
    }
    console.log(new Date());
    console.log('Function a() Ends');
}
a()
function b() {
console.log('Function B() starts');
   console.log(new Date());
    var a;
    var j;
    for (j=0; j<100000000; j++) {
      a = a + 1;
    }
    console.log(new Date());
    console.log('Function B() Ends');
}
b()

Os resultados mostraram no meu caso

Function a() starts
VM121:3 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:9 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:10 Function a() Ends
VM121:14 Function B() starts
VM121:15 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:21 Thu Apr 12 2018 15:20:26 GMT+0530 (India Standard Time)
VM121:22 Function B() Ends

Obrigado - MyFavs.in

myfavs.in
fonte
nos dois casos, você declara j fora do loop! X_x
john ktejik 06/04/19
Eu tentei no Chromium 81 com em letvez de vare a()tende a ser um pouco mais lento (como 120 vs 115 ms = ~ 6% = IMO insignificante)
mikiqex
-1

A questão aqui é basicamente declarar um var dentro de um loop. Basta pensar no que acontece se você fizer isso:

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

Acha que isto é certo? Não ... porque você não deseja declarar uma variável tantas vezes. Quando você declara uma variável dentro de um loop, ela não está declarando quantas vezes o loop é executado? Obviamente, isso lhe dará um tapa quando você estiver no modo 'use strict'. As pessoas discordaram de Crockford sem pensar na questão original.

Portanto, é sempre bom declarar variáveis ​​no topo - 1. Para facilitar a leitura, 2. Criar bons hábitos.

Vivek Pohre
fonte
1
"Quando você declara uma variável dentro de um loop, não está declarando quantas vezes o loop é executado?" <- Não, isso não está certo. A declaração da variável é içada, então tudo o que resta é a atribuição.
Matthias
-2

Em relação ao desempenho após a execução do teste no Chrome, Firefox e jsperf em um sistema operacional Linux, parece haver uma diferença de desempenho entre a declaração de variáveis ​​em um loop e fora de um loop. É uma pequena diferença, mas isso também é composto pela quantidade de iterações e pela quantidade de declarações de variáveis.

Portanto, para obter o melhor desempenho, eu teria que sugerir a declaração de variáveis ​​fora do loop. Ou melhor ainda, declare suas variáveis ​​em linha. Consultar exemplo.

// 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;
}

Observe como as variáveis ​​'al' e 'av' estão na linha de declaração do loop for. Esta declaração em linha me proporcionou um desempenho consistentemente melhor. Mesmo com a declaração de variáveis ​​fora do loop. Novamente, a diferença de desempenho é realmente pequena.

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

AlexanderElias
fonte
Para mim, seu teste deu dentro do loop. E no entanto isso não aconteceu, a diferença é muito pequena para concluir, e a resposta aceita explicar claramente não há diferença
Ulysse BN
À medida que as declarações de variáveis ​​são hasteadas, realmente não há diferença.
trincot