Vi a pergunta recente em que alguém disse isso para você, mas eles apenas significaram para matrizes. É considerado uma má prática para iterar através de matrizes, mas não necessariamente para iterar através de membros de um objeto.
mmurch
19
Muitas respostas com loops "for" como 'for (var i = 0; i <hColl.length; i ++) {}' são comparadas com 'var i = hColl.length; while (i--) {} 'que, quando é possível usar a última forma, é substancialmente mais rápido. Eu sei que isso é tangencial, mas pensei em adicionar este pouco.
Mark Schultheiss
2
@ MarkSchultheiss, mas isso é iteração reversa. Existe outra versão da iteração direta mais rápida?
ma11hew28
5
O @Wynand usa o var i = hCol1.length; for (i;i;i--;) {}cache i, pois fará a diferença e simplifica o teste. - quanto mais antigo o navegador, maior a diferença entre fore whileSEMPRE armazena em cache o contador "i" - e, claro, o negativo nem sempre se encaixa na situação, e o negativo, embora obfuscate o código seja um pouco para algumas pessoas. e observe var i = 1000; for (i; i; i--) {}e var b =1000 for (b; b--;) {}onde eu vou de 1000 para 1 eb vai de 999 a 0. - quanto mais antigo o navegador, mais o tempo tende a favorecer o desempenho.
Mark Schultheiss
9
Você também pode ser inteligente. for(var i = 0, l = myArray.length; i < l; ++i) ...é o mais rápido e melhor que você pode obter com a iteração direta.
Mathieu Amiot
Respostas:
1557
A razão é que uma construção:
var a =[];// Create a new empty array.
a[5]=5;// Perfectly legal JavaScript that resizes the array.for(var i =0; i < a.length; i++){// Iterate over numeric indexes from 0 to 5, as everyone expects.
console.log(a[i]);}/* Will display:
undefined
undefined
undefined
undefined
undefined
5
*/
Considere também que as bibliotecas JavaScript podem fazer coisas assim, o que afetará qualquer matriz que você criar:
// Somewhere deep in your JavaScript library...Array.prototype.foo =1;// Now you have no idea what the below code will do.var a =[1,2,3,4,5];for(var x in a){// Now foo is a part of EVERY array and // will show up here as a value of 'x'.
console.log(x);}/* Will display:
0
1
2
3
4
foo
*/
Historicamente, alguns navegadores até iteravam sobre 'comprimento', 'toString' etc.!
9990
398
Lembre-se de usar em (var x in a)vez de (x in a)- não queira criar um global.
Chris Morgan
78
A primeira questão não é um motivo para ser ruim, apenas uma diferença na semântica. A segunda questão parece-me uma razão (além de conflitos entre bibliotecas que fazem o mesmo) que alterar o protótipo de um tipo de dados interno é ruim, e não para .. é ruim.
Stewart
86
@ Stewart: Todos os objetos em JS são associativos. Uma matriz JS é um objeto; portanto, também é associativo, mas não é para isso que serve. Se você deseja percorrer as chaves de um objeto , use for (var key in object). Se você deseja iterar sobre os elementos de uma matriz , use for(var i = 0; i < array.length; i += 1).
Martijn
42
Você disse para o primeiro exemplo, que itera sobre índices numéricos de 0 a 4, como todos esperam , espero que itereça de 0 a 5 ! Como se você adicionar um elemento na posição 5, a matriz terá 6 elementos (5 deles indefinidos).
stivlo
393
A for-indeclaração por si só não é uma "má prática", no entanto, pode ser mal utilizada , por exemplo, para iterar sobre matrizes ou objetos semelhantes a matrizes.
O objetivo da for-ininstrução é enumerar as propriedades do objeto. Essa declaração aparecerá na cadeia de protótipos, também enumerando as propriedades herdadas , algo que às vezes não é desejado.
Além disso, a ordem da iteração não é garantida pela especificação., Significando que se você deseja "iterar" um objeto de matriz, com esta instrução, você não pode ter certeza de que as propriedades (índices da matriz) serão visitadas na ordem numérica.
Por exemplo, em JScript (IE <= 8), a ordem de enumeração mesmo nos objetos Array é definida conforme as propriedades foram criadas:
var array =[];
array[2]='c';
array[1]='b';
array[0]='a';for(var p in array){//... p will be "2", "1" and "0" on IE}
Além disso, falando sobre propriedades herdadas, se você, por exemplo, estender o Array.prototypeobjeto (como algumas bibliotecas como o MooTools), essas propriedades também serão enumeradas:
Array.prototype.last =function(){returnthis[this.length-1];};for(var p in []){// an empty array// last will be enumerated}
Como eu disse antes, para iterar sobre matrizes ou objetos semelhantes a matrizes, a melhor coisa é usar um loop seqüencial , como um loop simples for/ antigo while.
Quando você deseja enumerar apenas as próprias propriedades de um objeto (aquelas que não são herdadas), você pode usar o hasOwnPropertymétodo:
for(var prop in obj){if(obj.hasOwnProperty(prop)){// prop is not inherited}}
E algumas pessoas até recomendam chamar o método diretamente Object.prototypepara evitar problemas se alguém adicionar uma propriedade nomeada hasOwnPropertyao nosso objeto:
for(var prop in obj){if(Object.prototype.hasOwnProperty.call(obj, prop)){// prop is not inherited}}
Pergunta sobre o último ponto sobre "hasOwnProperty": se alguém substituir "hasOwnProperty" em um objeto, você terá problemas. Mas você não terá os mesmos problemas se alguém substituir "Object.prototype.hasOwnProperty"? De qualquer maneira, eles estão estragando tudo e não é sua responsabilidade, certo?
Scott Rippey
Você diz que for..innão é uma prática ruim, mas pode ser mal utilizada. Você tem um exemplo do mundo real de boas práticas, onde realmente deseja examinar todas as propriedades de um objeto, incluindo propriedades herdadas?
com essa resposta eu achei que pode acessar o valor comfor (var p in array) { array[p]; }
equiman
117
Há três razões pelas quais você não deve usar for..inpara iterar sobre os elementos da matriz:
for..infará um loop sobre todas as propriedades próprias e herdadas do objeto da matriz que não são DontEnum; isso significa que se alguém adicionar propriedades ao objeto específico da matriz (existem razões válidas para isso - eu já fiz isso) ou alterado Array.prototype(o que é considerado uma má prática no código que deve funcionar bem com outros scripts), essas propriedades serão ser iterado também; propriedades herdadas podem ser excluídas marcando hasOwnProperty(), mas isso não ajudará nas propriedades definidas no próprio objeto da matriz
for..in não é garantido para preservar a ordenação de elementos
é lento porque você precisa percorrer todas as propriedades do objeto array e toda a cadeia de protótipos e ainda obterá apenas o nome da propriedade, ou seja, para obter o valor, será necessária uma pesquisa adicional
Porque for ... in enumera através do objeto que contém a matriz, não a própria matriz. Se eu adicionar uma função à cadeia de protótipos de matrizes, ela também será incluída. Ou seja,
Array.prototype.myOwnFunction =function(){ alert(this);}
a =newArray();
a[0]='foo';
a[1]='bar';for(x in a){
document.write(x +' = '+ a[x]);}
Isto irá escrever:
0 = foo
1 = bar
myOwnFunction = function () {alert (this); }
E como você nunca pode ter certeza de que nada será adicionado à cadeia de protótipos, use um loop for para enumerar a matriz:
Matrizes são objetos, não há "objeto que retenha a matriz".
RobG
41
Isoladamente, não há nada errado em usar a entrada nas matrizes. For-in itera sobre os nomes de propriedades de um objeto e, no caso de uma matriz "pronta para uso", as propriedades correspondem aos índices da matriz. (As propriedades internas como length, toStringe assim por diante, não estão incluídas na iteração.)
No entanto, se o seu código (ou a estrutura que você está usando) adicionar propriedades personalizadas às matrizes ou ao protótipo da matriz, essas propriedades serão incluídas na iteração, o que provavelmente não é o que você deseja.
Algumas estruturas JS, como Prototype, modificam o protótipo Array. Outras estruturas, como o JQuery, não, portanto, com o JQuery, você pode usar o for-in com segurança.
Se você estiver em dúvida, provavelmente não deve usar o for-in.
Uma maneira alternativa de iterar através de uma matriz é usar um loop for:
for(var ix=0;ix<arr.length;ix++) alert(ix);
No entanto, isso tem um problema diferente. O problema é que uma matriz JavaScript pode ter "buracos". Se você definir arrcomo:
var arr =["hello"];
arr[100]="goodbye";
Em seguida, a matriz possui dois itens, mas um comprimento de 101. Usar for-in produzirá dois índices, enquanto o loop for produzirá 101 índices, nos quais o 99 tem um valor de undefined.
Resposta mais longa: simplesmente não vale a pena, mesmo que a ordem sequencial dos elementos e o desempenho ideal não sejam necessários.
Resposta longa: não vale a pena ...
O uso for (var property in array)fará com arrayque seja iterado como um objeto , atravessando a cadeia de protótipos de objetos e, finalmente, executando mais lentamente que um forloop baseado em índice .
for (... in ...) não é garantido o retorno das propriedades do objeto em ordem seqüencial, como seria de esperar.
O uso hasOwnProperty()e as !isNaN()verificações para filtrar as propriedades do objeto são uma sobrecarga adicional, o que resulta em um desempenho ainda mais lento e nega o principal motivo para usá-lo em primeiro lugar, ou seja, devido ao formato mais conciso.
Por esses motivos, nem sequer existe uma compensação aceitável entre desempenho e conveniência. Realmente não há benefício, a menos que a intenção seja manipular a matriz como um objeto e executar operações nas propriedades do objeto da matriz.
Além dos motivos apresentados em outras respostas, talvez você não queira usar a estrutura "for ... in" se precisar fazer contas com a variável counter, porque o loop itera os nomes das propriedades do objeto e, portanto, a variável é uma string.
Você pode usar o prefixo em +vez de, a parseIntmenos que realmente precise de um número inteiro ou ignore caracteres inválidos.
22912 Konrad Borowski
Além disso, o uso parseInt()não é recomendado. Experimente parseInt("025");e vai falhar.
Derek朕會功夫
6
@Derek 功夫 會 功夫 - você pode definitivamente usar parseInt. O problema é que, se você não incluir o radical, navegadores mais antigos podem tentar interpretar o número (assim, 025 se torna octal). Isso foi corrigido no ECMAScript 5, mas ainda acontece com números começando com "0x" (ele interpreta o número como hexadecimal). Para estar no lado seguro, use a raiz para especificar o número como assim parseInt("025", 10)- que especifica base 10.
A mecânica e a ordem de enumerar as propriedades ... não estão especificadas ...
(Ênfase minha.)
Isso significa que, se um navegador quisesse, ele poderia passar pelas propriedades na ordem em que foram inseridos. Ou em ordem numérica. Ou em ordem lexical (onde "30" vem antes de "4"! Lembre-se de que todas as chaves de objetos - e, portanto, todos os índices de array - são na verdade cadeias de caracteres, o que faz todo o sentido). Poderia passar por eles por bucket, se implementasse objetos como tabelas de hash. Ou pegue algo disso e adicione "para trás". Um navegador pode até repetir aleatoriamente e estar em conformidade com ECMA-262, desde que visite cada propriedade exatamente uma vez.
Na prática, a maioria dos navegadores atualmente gosta de iterar aproximadamente na mesma ordem. Mas não há nada dizendo que eles precisam. Isso é específico da implementação e pode mudar a qualquer momento, se for encontrada outra maneira de ser muito mais eficiente.
De qualquer maneira, for... não intraz conotação de ordem. Se você se preocupa com a ordem, seja explícito e use um forloop regular com um índice.
Como outros já disseram, você pode obter chaves que não estão no seu array ou que são herdadas do protótipo. Portanto, se, digamos, uma biblioteca adicionar uma propriedade aos protótipos de matriz ou objeto:
Array.prototype.someProperty =true
Você o obterá como parte de toda matriz:
for(var item in [1,2,3]){
console.log(item)// will log 1,2,3 but also "someProperty"}
você pode resolver isso com o método hasOwnProperty:
var ary =[1,2,3];for(var item in ary){if(ary.hasOwnProperty(item)){
console.log(item)// will log only 1,2,3}}
mas isso é verdade para iterar sobre qualquer objeto com um loop for-in.
Dois
Geralmente, a ordem dos itens em uma matriz é importante, mas o loop for-in não necessariamente itera na ordem correta, porque trata a matriz como um objeto, que é a maneira como é implementada em JS, e não como uma matriz. Parece uma coisa pequena, mas pode realmente estragar os aplicativos e é difícil de depurar.
Object.keys(a).forEach( function(item) { console.log(item) } )itere sobre uma matriz de chaves de propriedade próprias, não aquelas herdadas do protótipo.
precisa
2
É verdade, mas como o loop for-in, ele não estará necessariamente na ordem correta do índice. Além disso, ele não funcionará em navegadores antigos que não suportam o ES5.
No firefox 3, você também pode usar arr.forEach ou for (var [i, v] no Iterator (arr)) {}, mas nenhum desses funciona no IE, embora você mesmo possa escrever o método forEach.
vava
e praticamente toda biblioteca também possui seu próprio método para isso.
vava
5
Esta resposta está errada. "comprimento" não será incluído na iteração for-in. São apenas as propriedades que você adiciona que estão incluídas.
JacquesB
16
Eu não acho que tenho muito a acrescentar, por exemplo. A resposta do Triptych ou a resposta do CMS sobre por que o uso for...indeve ser evitado em alguns casos.
No entanto, gostaria de acrescentar que nos navegadores modernos existe uma alternativa for...inque pode ser usada nos casos em for...inque não pode ser usada. Essa alternativa é for...of:
for(var item of items){
console.log(item);}
Nota :
Infelizmente, nenhuma versão do Internet Explorer suporta for...of(o Edge 12 ou superior), portanto, você terá que esperar um pouco mais até poder usá-lo no código de produção do lado do cliente. No entanto, deve ser seguro usar no código JS do lado do servidor (se você usar o Node.js. ).
@georgeawg Você quis dizer for-of, não for-in, certo?
ᆼ ᆺ ᆼ
15
O problema com for ... in ...- e isso só se torna um problema quando um programador realmente não entende a linguagem; não é realmente um bug ou algo assim - é que itera sobre todos os membros de um objeto (bem, todos os membros enumeráveis , mas isso é um detalhe por enquanto). Quando você deseja iterar apenas as propriedades indexadas de uma matriz, a única maneira garantida de manter as coisas semanticamente consistentes é usar um índice inteiro (ou seja, um for (var i = 0; i < array.length; ++i)loop de estilo).
Qualquer objeto pode ter propriedades arbitrárias associadas a ele. Não haveria nada de terrível em carregar propriedades adicionais em uma instância de matriz, em particular. O código que deseja ver apenas propriedades indexadas de matriz, portanto, deve se ater a um índice inteiro. Código que está totalmente ciente do que for ... inrealmente precisa ver todas as propriedades, então tudo bem também.
Boa explicação Pointy. Apenas curioso. Se eu tivesse uma matriz que estivesse dentro de um objeto com propriedades de multiplicação e for in, em comparação com um loop for regular, essas matrizes seriam iteradas. (o que, em essência, um desempenho lento, certo?)
NiCk Newman
2
@NiCkNewman bem o objeto que você referência depois inem um for ... inloop apenas
Pointy
Eu vejo. Apenas curioso, porque eu tenho objetos e matrizes dentro do meu objeto principal do jogo e queria saber se a entrada seria mais dolorosa do que simplesmente um loop for regular nos índices.
NiCk Newman 31/07/2015
@NiCkNewman bem, o tema de toda essa pergunta é que você não deve usar for ... inmatrizes; existem muitas boas razões para não fazê-lo. Não é tanto uma questão de desempenho, mas uma questão de "certifique-se de que não quebre".
Pointy
Bem, meus objetos são tecnicamente armazenados em uma matriz, por isso fiquei preocupado, algo como [{a:'hey',b:'hi'},{a:'hey',b:'hi'}]:, mas sim, eu entendo.
NiCk Newman 31/07/2015
9
Além disso, devido à semântica, a maneira como for, intrata as matrizes (isto é, o mesmo que qualquer outro objeto JavaScript) não está alinhada com outros idiomas populares.
// C#char[] a =newchar[]{'A','B','C'};
foreach (char x in a)System.Console.Write(x);//Output: "ABC"// Javachar[] a ={'A','B','C'};for(char x : a)System.out.print(x);//Output: "ABC"// PHP
$a = array('A','B','C');
foreach ($a as $x) echo $x;//Output: "ABC"// JavaScriptvar a =['A','B','C'];for(var x in a) document.write(x);//Output: "012"
TL&DR: Usar o for inloop em matrizes não é ruim, na verdade, é o contrário.
Eu acho que o for inloop é uma jóia de JS, se usado corretamente em matrizes. Espera-se que você tenha controle total sobre o seu software e saiba o que está fazendo. Vamos ver as desvantagens mencionadas e refutá-las uma a uma.
Ele percorre as propriedades herdadas também: Antes de tudo, qualquer extensão ao Array.prototypedeve ter sido feita usando-se Object.defineProperty()e seu enumerabledescritor deve estar definido como false. Qualquer biblioteca que não esteja fazendo isso não deve ser usada.
As propriedades adicionadas posteriormente à cadeia de herança são contadas: Ao fazer a subclassificação de matrizes por Object.setPrototypeOfou por Classe extend. Você deve novamente usar o Object.defineProperty()que por padrão define os descritores de propriedade writable, enumerablee configurablecomo false. Vamos ver um exemplo de subclassificação de matriz aqui ...
functionStack(...a){var stack =newArray(...a);Object.setPrototypeOf(stack,Stack.prototype);return stack;}Stack.prototype =Object.create(Array.prototype);// now stack has full access to array methods.Object.defineProperty(Stack.prototype,"constructor",{value:Stack});// now Stack is a proper constructorObject.defineProperty(Stack.prototype,"peak",{value:function(){// add Stack "only" methods to the Stack.prototype.returnthis[this.length-1];}});var s =newStack(1,2,3,4,1);
console.log(s.peak());
s[s.length]=7;
console.log("length:",s.length);
s.push(42);
console.log(JSON.stringify(s));
console.log("length:",s.length);for(var i in s) console.log(s[i]);
Então você vê que o for inloop agora está seguro, pois você se preocupou com o seu código.
O for inciclo é lento: inferno não. É, de longe, o método mais rápido de iteração, se você fizer um loop sobre matrizes esparsas, necessárias de tempos em tempos. Este é um dos truques de desempenho mais importantes que se deve conhecer. Vamos ver um exemplo. Vamos fazer um loop sobre uma matriz esparsa.
var a =[];
a[0]="zero";
a[10000000]="ten million";
console.time("for loop on array a:");for(var i=0; i < a.length; i++) a[i]&& console.log(a[i]);
console.timeEnd("for loop on array a:");
console.time("for in loop on array a:");for(var i in a) a[i]&& console.log(a[i]);
console.timeEnd("for in loop on array a:");
@ Ravi Shanker Reddy Boa configuração de benchmarking. Como mencionei na minha resposta, o for inloop ofusca os outros "se" a matriz é escassa e, mais, se fica maior em tamanho. Então, reorganizei o teste de bancada para uma matriz esparsa arr, de tamanho ~ 10000, com apenas 50 itens escolhidos aleatoriamente entre [42,"test",{t:1},null, void 0]os índices aleatórios. Você notará imediatamente a diferença. - >> Confira aqui << - .
Redu
8
Além dos outros problemas, a sintaxe "for..in" é provavelmente mais lenta, porque o índice é uma sequência, não um número inteiro.
var a =["a"]for(var i in a)
alert(typeof i)// 'string'for(var i =0; i < a.length; i++)
alert(typeof i)// 'number'
Provavelmente não importa muito. Elementos de matriz são propriedades de um objeto com base em Matriz ou semelhante a uma matriz, e todas as propriedades do objeto possuem chaves de sequência. A menos que seu mecanismo JS o otimize de alguma forma, mesmo se você usasse um número, ele acabaria sendo transformado em uma sequência de caracteres para a pesquisa.
cHao 6/06/12
Independentemente de qualquer problema de desempenho, se você é novo no JavaScript, use var i in ae espere que o índice seja um número inteiro; em seguida, faça algo como a[i+offset] = <value>colocar valores completamente nos lugares errados. ("1" + 1 == "11").
Szmoore
8
Um aspecto importante é que for...inapenas itera as propriedades contidas em um objeto cujo atributo de propriedade enumerável esteja definido como true. Portanto, se alguém tentar iterar sobre um objeto usando , propriedades arbitrárias poderão ser perdidas se seu atributo de propriedade enumerável for falso. É bem possível alterar o atributo de propriedade enumerável para objetos Array normais, para que certos elementos não sejam enumerados. Embora, em geral, os atributos de propriedade tendam a se aplicar às propriedades da função dentro de um objeto.for...in
Pode-se verificar o valor do atributo de propriedade enumerável de uma propriedade:
myobject.propertyIsEnumerable('myproperty')
Ou para obter todos os quatro atributos de propriedade:
Esse é um recurso disponível no ECMAScript 5 - nas versões anteriores não era possível alterar o valor do atributo de propriedade enumerável (ele sempre era definido como true).
O for/ intrabalha com dois tipos de variáveis: hashtables (matrizes associativas) e array (não associativas).
O JavaScript determinará automaticamente a maneira como ele passa pelos itens. Portanto, se você souber que sua matriz é realmente não associativa, poderá usar for (var i=0; i<=arrayLen; i++)e pular a iteração de detecção automática.
Mas, na minha opinião, é melhor usar for/ in, o processo necessário para a detecção automática é muito pequeno.
Uma resposta real para isso dependerá de como o navegador analisa / interpreta o código JavaScript. Pode mudar entre navegadores.
Não consigo pensar em outros propósitos para não usar for/ in;
//Non-associativevar arr =['a','b','c'];for(var i in arr)
alert(arr[i]);//Associativevar arr ={
item1 :'a',
item2 :'b',
item3 :'c'};for(var i in arr)
alert(arr[i]);
Não é suficiente - é perfeitamente aceitável adicionar propriedades nomeadas arbitrárias a instâncias de matriz, e elas serão testadas a truepartir de hasOwnProperty()verificações.
Pointy
Bom ponto, obrigado. Eu nunca fui bobo o suficiente para fazer isso com uma matriz, então não considerei isso!
JAL
1
@ Pointy Eu não testei isso, mas talvez isso possa ser superado usando uma isNaNverificação no nome de cada propriedade.
WynandB
1
@Wynand idéia interessante; no entanto, eu realmente não vejo por que vale a pena tentar iterar com um índice numérico simples.
Pointy
@WynandB desculpe pelo problema, mas sinto que uma correção está em ordem: isNaNé para verificar se uma variável é o valor especial NaN ou não, ela não pode ser usada para verificar outras coisas além de números (você pode usar um método regular typeof para isso).
doldt
6
Não é necessariamente ruim (com base no que você está fazendo), mas no caso de matrizes, se algo foi adicionado Array.prototype, você obterá resultados estranhos. Onde você espera que esse loop seja executado três vezes:
var arr =['a','b','c'];for(var key in arr){...}
Se uma função chamada helpfulUtilityMethodfoi adicionado ao Array's prototype, então o seu ciclo acabaria sendo executado quatro vezes: keyseria 0, 1, 2, e helpfulUtilityMethod. Se você estava esperando apenas números inteiros, opa.
Apenas uma observação sobre SO - não há 'acima' porque os comentários mudam de ordem na página o tempo todo. Portanto, não sabemos realmente qual comentário você quer dizer. É bom dizer "no comentário de x pessoa" por esse motivo.
JAL
@JAL ... ou adicione o link permanente à resposta.
WynandB
5
Usar o for...inloop para uma matriz não está errado, embora eu possa adivinhar por que alguém lhe disse isso:
1.) Já existe uma função ou método de ordem superior que tem esse objetivo para uma matriz, mas tem mais funcionalidade e sintaxe mais enxuta, chamada 'forEach': Array.prototype.forEach(function(element, index, array) {} );
2.) Matrizes sempre ter um comprimento, mas for...ine forEachnão executar uma função para qualquer valor que é 'undefined', apenas para os índices que têm um valor definido. Portanto, se você atribuir apenas um valor, esses loops executarão uma função apenas uma vez, mas, como uma matriz é enumerada, ela sempre terá um comprimento até o índice mais alto com um valor definido, mas esse comprimento poderá passar despercebido ao usá-los. rotações.
3.) O padrão para loop executará uma função quantas vezes você definir nos parâmetros e, como uma matriz é numerada, faz mais sentido definir quantas vezes você deseja executar uma função. Diferentemente dos outros loops, o loop for pode executar uma função para cada índice na matriz, independentemente de o valor estar definido ou não.
Em essência, você pode usar qualquer loop, mas lembre-se exatamente de como eles funcionam. Entenda as condições sob as quais os diferentes loops reiteram, suas funcionalidades separadas e perceba que serão mais ou menos apropriados para diferentes cenários.
Além disso, pode ser considerado uma prática melhor usar o forEachmétodo do que o for...inloop em geral, porque é mais fácil escrever e tem mais funcionalidade, portanto, você pode adquirir o hábito de usar apenas esse método e padrão, mas seu ligar.
Veja abaixo que os dois primeiros loops executam apenas as instruções console.log uma vez, enquanto o loop for padrão executa a função quantas vezes for especificada, nesse caso, array.length = 6.
var arr =[];
arr[5]='F';for(var index in arr){
console.log(index);
console.log(arr[index]);
console.log(arr)}// 5// 'F'// => (6) [undefined x 5, 6]
arr.forEach(function(element, index, arr){
console.log(index);
console.log(element);
console.log(arr);});// 5// 'F'// => Array (6) [undefined x 5, 6]for(var index =0; index < arr.length; index++){
console.log(index);
console.log(arr[index]);
console.log(arr);};// 0// undefined// => Array (6) [undefined x 5, 6]// 1// undefined// => Array (6) [undefined x 5, 6]// 2// undefined// => Array (6) [undefined x 5, 6]// 3// undefined// => Array (6) [undefined x 5, 6]// 4// undefined// => Array (6) [undefined x 5, 6]// 5// 'F'// => Array (6) [undefined x 5, 6]
Aqui estão as razões pelas quais essa é (geralmente) uma má prática:
for...inos loops iteram sobre todas as suas próprias propriedades enumeráveis e as propriedades enumeráveis de seus protótipos. Normalmente, em uma iteração de matriz, queremos apenas iterar sobre a própria matriz. E mesmo que você mesmo não adicione nada à matriz, suas bibliotecas ou estrutura podem adicionar algo.
Exemplo :
Array.prototype.hithere ='hithere';var array =[1,2,3];for(let el in array){// the hithere property will also be iterated over
console.log(el);}
for...inos loops não garantem uma ordem de iteração específica . Embora a ordem seja vista na maioria dos navegadores modernos atualmente, ainda não há garantia de 100%.
for...inos loops ignoram os undefinedelementos da matriz, isto é, elementos da matriz que ainda não foram atribuídos.
Exemplo :
const arr =[];
arr[3]='foo';// resize the array to 4
arr[4]=undefined;// add another element with value undefined to it// iterate over the array, a for loop does show the undefined elementsfor(let i =0; i < arr.length; i++){
console.log(arr[i]);}
console.log('\n');// for in does ignore the undefined elementsfor(let el in arr){
console.log(arr[el]);}
for ... in é útil ao trabalhar em um objeto em JavaScript, mas não em uma matriz, mas ainda não podemos dizer que é um caminho errado, mas não recomendado, veja este exemplo abaixo usando o loop for ... in :
let txt ="";const person ={fname:"Alireza", lname:"Dezfoolian", age:35};for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
OK, vamos fazer isso com o Array agora:
let txt ="";const person =["Alireza","Dezfoolian",35];for(const x in person){
txt += person[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35
Como você vê o resultado, o mesmo ...
Mas vamos tentar algo, vamos criar um protótipo para o Array ...
Array.prototype.someoneelse ="someoneelse";
Agora criamos um novo Array ();
let txt ="";const arr =newArray();
arr[0]='Alireza';
arr[1]='Dezfoolian';
arr[2]=35;for(x in arr){
txt += arr[x]+" ";}
console.log(txt);//Alireza Dezfoolian 35 someoneelse
Você vê a outra pessoa !!! ... Na verdade, estamos fazendo um loop através do novo objeto Array neste caso!
Então essa é uma das razões pelas quais precisamos usar for..in com cuidado, mas nem sempre é o caso ...
Como os elementos JavaScript são salvos como propriedades padrão do objeto, não é aconselhável iterar as matrizes JavaScript usando loops for ... in porque os elementos normais e todas as propriedades enumeráveis serão listadas.
embora não seja especificamente abordado por esta pergunta, eu acrescentaria que há uma boa razão para nunca usar ... com um NodeList(como seria obtido em uma querySelectorAllchamada, pois ele não vê os elementos retornados) iterando apenas sobre as propriedades NodeList.
var i = hCol1.length; for (i;i;i--;) {}
cache i, pois fará a diferença e simplifica o teste. - quanto mais antigo o navegador, maior a diferença entrefor
ewhile
SEMPRE armazena em cache o contador "i" - e, claro, o negativo nem sempre se encaixa na situação, e o negativo, emboraobfuscate
o código seja um pouco para algumas pessoas. e observevar i = 1000; for (i; i; i--) {}
evar b =1000 for (b; b--;) {}
onde eu vou de 1000 para 1 eb vai de 999 a 0. - quanto mais antigo o navegador, mais o tempo tende a favorecer o desempenho.for(var i = 0, l = myArray.length; i < l; ++i) ...
é o mais rápido e melhor que você pode obter com a iteração direta.Respostas:
A razão é que uma construção:
Às vezes, pode ser totalmente diferente do outro:
Considere também que as bibliotecas JavaScript podem fazer coisas assim, o que afetará qualquer matriz que você criar:
fonte
(var x in a)
vez de(x in a)
- não queira criar um global.for (var key in object)
. Se você deseja iterar sobre os elementos de uma matriz , usefor(var i = 0; i < array.length; i += 1)
.A
for-in
declaração por si só não é uma "má prática", no entanto, pode ser mal utilizada , por exemplo, para iterar sobre matrizes ou objetos semelhantes a matrizes.O objetivo da
for-in
instrução é enumerar as propriedades do objeto. Essa declaração aparecerá na cadeia de protótipos, também enumerando as propriedades herdadas , algo que às vezes não é desejado.Além disso, a ordem da iteração não é garantida pela especificação., Significando que se você deseja "iterar" um objeto de matriz, com esta instrução, você não pode ter certeza de que as propriedades (índices da matriz) serão visitadas na ordem numérica.
Por exemplo, em JScript (IE <= 8), a ordem de enumeração mesmo nos objetos Array é definida conforme as propriedades foram criadas:
Além disso, falando sobre propriedades herdadas, se você, por exemplo, estender o
Array.prototype
objeto (como algumas bibliotecas como o MooTools), essas propriedades também serão enumeradas:Como eu disse antes, para iterar sobre matrizes ou objetos semelhantes a matrizes, a melhor coisa é usar um loop seqüencial , como um loop simples
for
/ antigowhile
.Quando você deseja enumerar apenas as próprias propriedades de um objeto (aquelas que não são herdadas), você pode usar o
hasOwnProperty
método:E algumas pessoas até recomendam chamar o método diretamente
Object.prototype
para evitar problemas se alguém adicionar uma propriedade nomeadahasOwnProperty
ao nosso objeto:fonte
for..in
são muito mais lentos que os loops "normais".for..in
não é uma prática ruim, mas pode ser mal utilizada. Você tem um exemplo do mundo real de boas práticas, onde realmente deseja examinar todas as propriedades de um objeto, incluindo propriedades herdadas?for (var p in array) { array[p]; }
Há três razões pelas quais você não deve usar
for..in
para iterar sobre os elementos da matriz:for..in
fará um loop sobre todas as propriedades próprias e herdadas do objeto da matriz que não sãoDontEnum
; isso significa que se alguém adicionar propriedades ao objeto específico da matriz (existem razões válidas para isso - eu já fiz isso) ou alteradoArray.prototype
(o que é considerado uma má prática no código que deve funcionar bem com outros scripts), essas propriedades serão ser iterado também; propriedades herdadas podem ser excluídas marcandohasOwnProperty()
, mas isso não ajudará nas propriedades definidas no próprio objeto da matrizfor..in
não é garantido para preservar a ordenação de elementosé lento porque você precisa percorrer todas as propriedades do objeto array e toda a cadeia de protótipos e ainda obterá apenas o nome da propriedade, ou seja, para obter o valor, será necessária uma pesquisa adicional
fonte
Porque for ... in enumera através do objeto que contém a matriz, não a própria matriz. Se eu adicionar uma função à cadeia de protótipos de matrizes, ela também será incluída. Ou seja,
Isto irá escrever:
E como você nunca pode ter certeza de que nada será adicionado à cadeia de protótipos, use um loop for para enumerar a matriz:
Isto irá escrever:
fonte
Isoladamente, não há nada errado em usar a entrada nas matrizes. For-in itera sobre os nomes de propriedades de um objeto e, no caso de uma matriz "pronta para uso", as propriedades correspondem aos índices da matriz. (As propriedades internas como
length
,toString
e assim por diante, não estão incluídas na iteração.)No entanto, se o seu código (ou a estrutura que você está usando) adicionar propriedades personalizadas às matrizes ou ao protótipo da matriz, essas propriedades serão incluídas na iteração, o que provavelmente não é o que você deseja.
Algumas estruturas JS, como Prototype, modificam o protótipo Array. Outras estruturas, como o JQuery, não, portanto, com o JQuery, você pode usar o for-in com segurança.
Se você estiver em dúvida, provavelmente não deve usar o for-in.
Uma maneira alternativa de iterar através de uma matriz é usar um loop for:
No entanto, isso tem um problema diferente. O problema é que uma matriz JavaScript pode ter "buracos". Se você definir
arr
como:Em seguida, a matriz possui dois itens, mas um comprimento de 101. Usar for-in produzirá dois índices, enquanto o loop for produzirá 101 índices, nos quais o 99 tem um valor de
undefined
.fonte
A partir de 2016 (ES6), poderemos usar
for…of
para iteração de matriz, como John Slegers já notou.Gostaria apenas de adicionar este código de demonstração simples, para tornar as coisas mais claras:
O console mostra:
Em outras palavras:
for...of
conta de 0 a 5 e também ignoraArray.prototype.foo
. Mostra valores de matriz .for...in
lista apenas os5
, ignorando índices de matriz indefinidos, mas adicionandofoo
. Ele mostra os nomes das propriedades da matriz .fonte
Resposta curta: simplesmente não vale a pena.
Resposta mais longa: simplesmente não vale a pena, mesmo que a ordem sequencial dos elementos e o desempenho ideal não sejam necessários.
Resposta longa: não vale a pena ...
for (var property in array)
fará comarray
que seja iterado como um objeto , atravessando a cadeia de protótipos de objetos e, finalmente, executando mais lentamente que umfor
loop baseado em índice .for (... in ...)
não é garantido o retorno das propriedades do objeto em ordem seqüencial, como seria de esperar.hasOwnProperty()
e as!isNaN()
verificações para filtrar as propriedades do objeto são uma sobrecarga adicional, o que resulta em um desempenho ainda mais lento e nega o principal motivo para usá-lo em primeiro lugar, ou seja, devido ao formato mais conciso.Por esses motivos, nem sequer existe uma compensação aceitável entre desempenho e conveniência. Realmente não há benefício, a menos que a intenção seja manipular a matriz como um objeto e executar operações nas propriedades do objeto da matriz.
fonte
Além dos motivos apresentados em outras respostas, talvez você não queira usar a estrutura "for ... in" se precisar fazer contas com a variável counter, porque o loop itera os nomes das propriedades do objeto e, portanto, a variável é uma string.
Por exemplo,
escreverá
enquanto que,
escreverá
Obviamente, isso pode ser facilmente superado, incluindo
no loop, mas a primeira estrutura é mais direta.
fonte
+
vez de, aparseInt
menos que realmente precise de um número inteiro ou ignore caracteres inválidos.parseInt()
não é recomendado. ExperimenteparseInt("025");
e vai falhar.parseInt
. O problema é que, se você não incluir o radical, navegadores mais antigos podem tentar interpretar o número (assim, 025 se torna octal). Isso foi corrigido no ECMAScript 5, mas ainda acontece com números começando com "0x" (ele interpreta o número como hexadecimal). Para estar no lado seguro, use a raiz para especificar o número como assimparseInt("025", 10)
- que especifica base 10.Além do fato de que
for
...in
circula todas as propriedades enumeráveis (que não são iguais a "todos os elementos da matriz"!), Consulte http://www.ecma-international.org/publications/files/ECMA-ST/Ecma -262.pdf , seção 12.6.4 (5ª edição) ou 13.7.5.15 (7ª edição):(Ênfase minha.)
Isso significa que, se um navegador quisesse, ele poderia passar pelas propriedades na ordem em que foram inseridos. Ou em ordem numérica. Ou em ordem lexical (onde "30" vem antes de "4"! Lembre-se de que todas as chaves de objetos - e, portanto, todos os índices de array - são na verdade cadeias de caracteres, o que faz todo o sentido). Poderia passar por eles por bucket, se implementasse objetos como tabelas de hash. Ou pegue algo disso e adicione "para trás". Um navegador pode até repetir aleatoriamente e estar em conformidade com ECMA-262, desde que visite cada propriedade exatamente uma vez.
Na prática, a maioria dos navegadores atualmente gosta de iterar aproximadamente na mesma ordem. Mas não há nada dizendo que eles precisam. Isso é específico da implementação e pode mudar a qualquer momento, se for encontrada outra maneira de ser muito mais eficiente.
De qualquer maneira,
for
... nãoin
traz conotação de ordem. Se você se preocupa com a ordem, seja explícito e use umfor
loop regular com um índice.fonte
Principalmente duas razões:
1
Como outros já disseram, você pode obter chaves que não estão no seu array ou que são herdadas do protótipo. Portanto, se, digamos, uma biblioteca adicionar uma propriedade aos protótipos de matriz ou objeto:
Você o obterá como parte de toda matriz:
você pode resolver isso com o método hasOwnProperty:
mas isso é verdade para iterar sobre qualquer objeto com um loop for-in.
Dois
Geralmente, a ordem dos itens em uma matriz é importante, mas o loop for-in não necessariamente itera na ordem correta, porque trata a matriz como um objeto, que é a maneira como é implementada em JS, e não como uma matriz. Parece uma coisa pequena, mas pode realmente estragar os aplicativos e é difícil de depurar.
fonte
Object.keys(a).forEach( function(item) { console.log(item) } )
itere sobre uma matriz de chaves de propriedade próprias, não aquelas herdadas do protótipo.array.forEach
inserindo determinado código em seus scripts. Consulte Polyfill developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Porque enumera através de campos de objetos, não de índices. Você pode obter valor com o índice "length" e duvido que você queira isso.
fonte
Eu não acho que tenho muito a acrescentar, por exemplo. A resposta do Triptych ou a resposta do CMS sobre por que o uso
for...in
deve ser evitado em alguns casos.No entanto, gostaria de acrescentar que nos navegadores modernos existe uma alternativa
for...in
que pode ser usada nos casos emfor...in
que não pode ser usada. Essa alternativa éfor...of
:Nota :
Infelizmente, nenhuma versão do Internet Explorer suporta
for...of
(o Edge 12 ou superior), portanto, você terá que esperar um pouco mais até poder usá-lo no código de produção do lado do cliente. No entanto, deve ser seguro usar no código JS do lado do servidor (se você usar o Node.js. ).fonte
for-of
, nãofor-in
, certo?O problema com
for ... in ...
- e isso só se torna um problema quando um programador realmente não entende a linguagem; não é realmente um bug ou algo assim - é que itera sobre todos os membros de um objeto (bem, todos os membros enumeráveis , mas isso é um detalhe por enquanto). Quando você deseja iterar apenas as propriedades indexadas de uma matriz, a única maneira garantida de manter as coisas semanticamente consistentes é usar um índice inteiro (ou seja, umfor (var i = 0; i < array.length; ++i)
loop de estilo).Qualquer objeto pode ter propriedades arbitrárias associadas a ele. Não haveria nada de terrível em carregar propriedades adicionais em uma instância de matriz, em particular. O código que deseja ver apenas propriedades indexadas de matriz, portanto, deve se ater a um índice inteiro. Código que está totalmente ciente do que
for ... in
realmente precisa ver todas as propriedades, então tudo bem também.fonte
for in
, em comparação com um loop for regular, essas matrizes seriam iteradas. (o que, em essência, um desempenho lento, certo?)in
em umfor ... in
loop apenasfor ... in
matrizes; existem muitas boas razões para não fazê-lo. Não é tanto uma questão de desempenho, mas uma questão de "certifique-se de que não quebre".[{a:'hey',b:'hi'},{a:'hey',b:'hi'}]
:, mas sim, eu entendo.Além disso, devido à semântica, a maneira como
for, in
trata as matrizes (isto é, o mesmo que qualquer outro objeto JavaScript) não está alinhada com outros idiomas populares.fonte
TL&DR: Usar o
for in
loop em matrizes não é ruim, na verdade, é o contrário.Eu acho que o
for in
loop é uma jóia de JS, se usado corretamente em matrizes. Espera-se que você tenha controle total sobre o seu software e saiba o que está fazendo. Vamos ver as desvantagens mencionadas e refutá-las uma a uma.Array.prototype
deve ter sido feita usando-seObject.defineProperty()
e seuenumerable
descritor deve estar definido comofalse
. Qualquer biblioteca que não esteja fazendo isso não deve ser usada.Object.setPrototypeOf
ou por Classeextend
. Você deve novamente usar oObject.defineProperty()
que por padrão define os descritores de propriedadewritable
,enumerable
econfigurable
comofalse
. Vamos ver um exemplo de subclassificação de matriz aqui ...Então você vê que o
for in
loop agora está seguro, pois você se preocupou com o seu código.for in
ciclo é lento: inferno não. É, de longe, o método mais rápido de iteração, se você fizer um loop sobre matrizes esparsas, necessárias de tempos em tempos. Este é um dos truques de desempenho mais importantes que se deve conhecer. Vamos ver um exemplo. Vamos fazer um loop sobre uma matriz esparsa.fonte
for in
loop ofusca os outros "se" a matriz é escassa e, mais, se fica maior em tamanho. Então, reorganizei o teste de bancada para uma matriz esparsaarr
, de tamanho ~ 10000, com apenas 50 itens escolhidos aleatoriamente entre[42,"test",{t:1},null, void 0]
os índices aleatórios. Você notará imediatamente a diferença. - >> Confira aqui << - .Além dos outros problemas, a sintaxe "for..in" é provavelmente mais lenta, porque o índice é uma sequência, não um número inteiro.
fonte
var i in a
e espere que o índice seja um número inteiro; em seguida, faça algo comoa[i+offset] = <value>
colocar valores completamente nos lugares errados. ("1" + 1 == "11").Um aspecto importante é que
for...in
apenas itera as propriedades contidas em um objeto cujo atributo de propriedade enumerável esteja definido como true. Portanto, se alguém tentar iterar sobre um objeto usando , propriedades arbitrárias poderão ser perdidas se seu atributo de propriedade enumerável for falso. É bem possível alterar o atributo de propriedade enumerável para objetos Array normais, para que certos elementos não sejam enumerados. Embora, em geral, os atributos de propriedade tendam a se aplicar às propriedades da função dentro de um objeto.for...in
Pode-se verificar o valor do atributo de propriedade enumerável de uma propriedade:
Ou para obter todos os quatro atributos de propriedade:
Esse é um recurso disponível no ECMAScript 5 - nas versões anteriores não era possível alterar o valor do atributo de propriedade enumerável (ele sempre era definido como true).
fonte
O
for
/in
trabalha com dois tipos de variáveis: hashtables (matrizes associativas) e array (não associativas).O JavaScript determinará automaticamente a maneira como ele passa pelos itens. Portanto, se você souber que sua matriz é realmente não associativa, poderá usar
for (var i=0; i<=arrayLen; i++)
e pular a iteração de detecção automática.Mas, na minha opinião, é melhor usar
for
/in
, o processo necessário para a detecção automática é muito pequeno.Uma resposta real para isso dependerá de como o navegador analisa / interpreta o código JavaScript. Pode mudar entre navegadores.
Não consigo pensar em outros propósitos para não usar
for
/in
;fonte
Array
é porqueObject
tambémfor ... in
trabalha com objetos. Não existe detecção automática.Porque ele iterará nas propriedades pertencentes aos objetos da cadeia de protótipos, se você não tomar cuidado.
Você pode usar
for.. in
, apenas verifique cada propriedade com hasOwnProperty .fonte
true
partir dehasOwnProperty()
verificações.isNaN
verificação no nome de cada propriedade.isNaN
é para verificar se uma variável é o valor especial NaN ou não, ela não pode ser usada para verificar outras coisas além de números (você pode usar um método regular typeof para isso).Não é necessariamente ruim (com base no que você está fazendo), mas no caso de matrizes, se algo foi adicionado
Array.prototype
, você obterá resultados estranhos. Onde você espera que esse loop seja executado três vezes:Se uma função chamada
helpfulUtilityMethod
foi adicionado aoArray
'sprototype
, então o seu ciclo acabaria sendo executado quatro vezes:key
seria0
,1
,2
, ehelpfulUtilityMethod
. Se você estava esperando apenas números inteiros, opa.fonte
Você deve usar o
for(var x in y)
único nas listas de propriedades, não nos objetos (como explicado acima).fonte
Usar o
for...in
loop para uma matriz não está errado, embora eu possa adivinhar por que alguém lhe disse isso:1.) Já existe uma função ou método de ordem superior que tem esse objetivo para uma matriz, mas tem mais funcionalidade e sintaxe mais enxuta, chamada 'forEach':
Array.prototype.forEach(function(element, index, array) {} );
2.) Matrizes sempre ter um comprimento, mas
for...in
eforEach
não executar uma função para qualquer valor que é'undefined'
, apenas para os índices que têm um valor definido. Portanto, se você atribuir apenas um valor, esses loops executarão uma função apenas uma vez, mas, como uma matriz é enumerada, ela sempre terá um comprimento até o índice mais alto com um valor definido, mas esse comprimento poderá passar despercebido ao usá-los. rotações.3.) O padrão para loop executará uma função quantas vezes você definir nos parâmetros e, como uma matriz é numerada, faz mais sentido definir quantas vezes você deseja executar uma função. Diferentemente dos outros loops, o loop for pode executar uma função para cada índice na matriz, independentemente de o valor estar definido ou não.
Em essência, você pode usar qualquer loop, mas lembre-se exatamente de como eles funcionam. Entenda as condições sob as quais os diferentes loops reiteram, suas funcionalidades separadas e perceba que serão mais ou menos apropriados para diferentes cenários.
Além disso, pode ser considerado uma prática melhor usar o
forEach
método do que ofor...in
loop em geral, porque é mais fácil escrever e tem mais funcionalidade, portanto, você pode adquirir o hábito de usar apenas esse método e padrão, mas seu ligar.Veja abaixo que os dois primeiros loops executam apenas as instruções console.log uma vez, enquanto o loop for padrão executa a função quantas vezes for especificada, nesse caso, array.length = 6.
fonte
Aqui estão as razões pelas quais essa é (geralmente) uma má prática:
for...in
os loops iteram sobre todas as suas próprias propriedades enumeráveis e as propriedades enumeráveis de seus protótipos. Normalmente, em uma iteração de matriz, queremos apenas iterar sobre a própria matriz. E mesmo que você mesmo não adicione nada à matriz, suas bibliotecas ou estrutura podem adicionar algo.Exemplo :
for...in
os loops não garantem uma ordem de iteração específica . Embora a ordem seja vista na maioria dos navegadores modernos atualmente, ainda não há garantia de 100%.for...in
os loops ignoram osundefined
elementos da matriz, isto é, elementos da matriz que ainda não foram atribuídos.Exemplo :
fonte
for ... in é útil ao trabalhar em um objeto em JavaScript, mas não em uma matriz, mas ainda não podemos dizer que é um caminho errado, mas não recomendado, veja este exemplo abaixo usando o loop for ... in :
OK, vamos fazer isso com o Array agora:
Como você vê o resultado, o mesmo ...
Mas vamos tentar algo, vamos criar um protótipo para o Array ...
Agora criamos um novo Array ();
Você vê a outra pessoa !!! ... Na verdade, estamos fazendo um loop através do novo objeto Array neste caso!
Então essa é uma das razões pelas quais precisamos usar for..in com cuidado, mas nem sempre é o caso ...
fonte
Um loop for ... in sempre enumera as chaves. As chaves de propriedades dos objetos são sempre String, mesmo as propriedades indexadas de uma matriz:
fonte
De https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Indexed_collections
fonte
embora não seja especificamente abordado por esta pergunta, eu acrescentaria que há uma boa razão para nunca usar ... com um
NodeList
(como seria obtido em umaquerySelectorAll
chamada, pois ele não vê os elementos retornados) iterando apenas sobre as propriedades NodeList.no caso de um único resultado, obtive:
o que explicava porque minha
for (node in nodes) node.href = newLink;
falha estava.fonte