Eu procurei, mas procurei forEach e não apenas for. como afirmado, em c # era um pouco diferente, e isso me confundiu :) #
4399 Dante1986
6
O ECMAScript & nbsp; 6 talvez contenha a construção "para ... de". Consulte para ... de (MDN) para obter mais informações. Você já pode experimentá-lo com versões recentes do Firefox.
Por outro lado, no Python é mais eficiente usar funções do que usar tradicionais para loops. (Considere que i < lene i++pode ser feito pelo motor, em vez de pelo intérprete.)
joeytwiddle
Respostas:
7022
TL; DR
Não use a for-inmenos que você o use com salvaguardas ou pelo menos esteja ciente do motivo pelo qual ele pode morder você.
Mas há muito mais para explorar, continue a ler ...
O JavaScript possui uma semântica poderosa para fazer loop através de matrizes e objetos semelhantes a matrizes. Dividi a resposta em duas partes: opções para matrizes genuínas e opções para coisas parecidas com matrizes , como o argumentsobjeto, outros objetos iteráveis (ES2015 +), coleções DOM e assim por diante.
Observarei rapidamente que você pode usar as opções do ES2015 agora , mesmo nos mecanismos ES5, transpilando o ES2015 para o ES5. Pesquise "transpiling ES2015" / "transpiling ES6" para obter mais ...
Ok, vejamos nossas opções:
Para matrizes reais
Você tem três opções no ECMAScript 5 ("ES5"), a versão mais amplamente suportada no momento, e mais duas adicionadas no ECMAScript 2015 ("ES2015", "ES6"):
Uso forEache afins (ES5 +)
Use um forloop simples
Use for-incorretamente
Use for-of(use um iterador implicitamente) (ES2015 +)
Use um iterador explicitamente (ES2015 +)
Detalhes:
1. Uso forEache afins
Em qualquer ambiente vagamente moderno (portanto, não no IE8) em que você tenha acesso aos Arrayrecursos adicionados pelo ES5 (diretamente ou usando polyfills), você pode usar forEach( spec| MDN):
var a =["a","b","c"];
a.forEach(function(entry){
console.log(entry);});
forEachaceita uma função de retorno de chamada e, opcionalmente, um valor para usar como thisao chamar esse retorno de chamada (não usado acima). O retorno de chamada é chamado para cada entrada na matriz, em ordem, ignorando entradas inexistentes em matrizes esparsas. Embora eu tenha usado apenas um argumento acima, o retorno de chamada é chamado com três: O valor de cada entrada, o índice dessa entrada e uma referência à matriz na qual você está iterando (caso sua função ainda não a tenha útil) )
A menos que você ofereça suporte a navegadores obsoletos como o IE8 (que o NetApps mostra com pouco mais de 4% de participação de mercado até o momento em que escrevemos em setembro de 2016), você pode usar felizmente forEachuma página da Web de uso geral sem nenhum calço. Se você precisar oferecer suporte a navegadores obsoletos, forEaché fácil fazer o shimming / polyfilling (pesquise "es5 shim" para várias opções).
forEach tem o benefício de que você não precisa declarar variáveis de indexação e valor no escopo que contém, pois elas são fornecidas como argumentos para a função de iteração e têm um escopo adequado para essa iteração.
Se você está preocupado com o custo de tempo de execução de uma chamada de função para cada entrada da matriz, não fique; detalhes .
Além disso, forEaché a função "loop through all all", mas o ES5 definiu várias outras funções úteis "percorrer a matriz e executar tarefas", incluindo:
every(para de repetir a primeira vez que o retorno de chamada retorna falseou algo está errado)
some(para de repetir a primeira vez que o retorno de chamada trueou algo verdadeiro)
filter(cria uma nova matriz, incluindo elementos onde a função de filtro retorna truee omite os que retornam false)
map (cria uma nova matriz a partir dos valores retornados pelo retorno de chamada)
reduce (cria um valor chamando repetidamente o retorno de chamada, transmitindo valores anteriores; consulte a especificação para obter detalhes; útil para resumir o conteúdo de uma matriz e muitas outras coisas)
reduceRight(como reduce, mas funciona em ordem decrescente em vez de crescente)
2. Use um forloop simples
Às vezes, os modos antigos são os melhores:
var index;var a =["a","b","c"];for(index =0; index < a.length;++index){
console.log(a[index]);}
Se o comprimento da matriz não vai mudar durante o ciclo, e é em código sensível ao desempenho (improvável), uma versão um pouco mais complicado agarrando o comprimento na frente pode ser um minúsculo pouco mais rápido:
var index, len;var a =["a","b","c"];for(index =0, len = a.length; index < len;++index){
console.log(a[index]);}
Mas, com os modernos mecanismos JavaScript, é raro você precisar aproveitar esse último pedaço de suco.
No ES2015 e superior, você pode tornar suas variáveis de índice e valor locais para o forloop:
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}//console.log(index); // would cause "ReferenceError: index is not defined"//console.log(value); // would cause "ReferenceError: value is not defined"
let a =["a","b","c"];for(let index =0; index < a.length;++index){let value = a[index];
console.log(index, value);}try{
console.log(index);}catch(e){
console.error(e);// "ReferenceError: index is not defined"}try{
console.log(value);}catch(e){
console.error(e);// "ReferenceError: value is not defined"}
E quando você faz isso, não só valuemas também indexé recriado para cada iteração do loop, ou seja, fechamentos criados no corpo do loop manter uma referência ao index(e value) criado para a iteração específica:
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
let divs = document.querySelectorAll("div");for(let index =0; index < divs.length;++index){
divs[index].addEventListener('click', e =>{
console.log("Index is: "+ index);});}
Se você tivesse cinco divs, obteria "O índice é: 0" se você clicou no primeiro e "O índice é: 4" se você clicou no último. Isso não funciona se você usar em varvez de let.
3. Use for-incorretamente
Você fará as pessoas dizerem para você usar for-in, mas não for-iné para isso . for-inpercorre as propriedades enumeráveis de um objeto , não os índices de uma matriz. O pedido não é garantido , nem mesmo no ES2015 (ES6). ES2015 + faz definir uma ordem para as propriedades do objeto (via [[OwnPropertyKeys]], [[Enumerate]]e as coisas que os utilizam como Object.getOwnPropertyKeys), mas não define que for-iniria seguir essa ordem; ES2020 fez, no entanto. (Detalhes nesta outra resposta .)
Os únicos casos de uso reais for-inem uma matriz são:
Você está usando propriedades que não são elementos e deseja incluí-las no loop
Observando apenas o primeiro exemplo: você pode for-invisitar esses elementos esparsos da matriz se usar as salvaguardas apropriadas:
// `a` is a sparse arrayvar key;var a =[];
a[0]="a";
a[10]="b";
a[10000]="c";for(key in a){if(a.hasOwnProperty(key)&&// These checks are/^0$|^[1-9]\d*$/.test(key)&&// explained
key <=4294967294// below){
console.log(a[key]);}}
Que o objeto tem sua própria propriedade com esse nome (não herdado de seu protótipo) e
Que a chave tem todos os dígitos decimais (por exemplo, forma normal de string, não notação científica) e
Que o valor da chave quando coagido a um número é <= 2 ^ 32 - 2 (que é 4.294.967.294). De onde vem esse número? Faz parte da definição de um índice de matriz na especificação . Outros números (não inteiros, números negativos, números maiores que 2 ^ 32 - 2) não são índices de matriz. A razão é 2 ^ 32 - 2 é que faz com que o maior valor de índice um menor que 2 ^ 32 - 1 , que é o valor máximo de uma matriz lengthpode ter. (Por exemplo, o comprimento de uma matriz se encaixa em um número inteiro não assinado de 32 bits.) (Adota o RobG por apontar em um comentário no meu blog que o meu teste anterior não estava certo.)
Você não faria isso em código embutido, é claro. Você escreveria uma função utilitária. Possivelmente:
// Utility function for antiquated environments without `forEach`var hasOwn =Object.prototype.hasOwnProperty;var rexNum =/^0$|^[1-9]\d*$/;function sparseEach(array, callback, thisArg){var index;for(var key in array){
index =+key;if(hasOwn.call(a, key)&&
rexNum.test(key)&&
index <=4294967294){
callback.call(thisArg, array[key], index, array);}}}var a =[];
a[5]="five";
a[10]="ten";
a[100000]="one hundred thousand";
a.b ="bee";
sparseEach(a,function(value, index){
console.log("Value at "+ index +" is "+ value);});
Sob as cobertas, ele obtém um iterador da matriz e passa por ela, obtendo os valores dela. Isso não tem o problema que usar for-inhas, porque usa um iterador definido pelo objeto (a matriz), e as matrizes definem que seus iteradores iteram pelas entradas (não pelas propriedades). Diferentemente for-indo ES5, a ordem na qual as entradas são visitadas é a ordem numérica de seus índices.
5. Use um iterador explicitamente (ES2015 +)
Às vezes, convém usar um iterador explicitamente . Você pode fazer isso também, embora seja muito mais complicado do que isso for-of. Se parece com isso:
const a =["a","b","c"];const it = a.values();let entry;while(!(entry = it.next()).done){
console.log(entry.value);}
O iterador é um objeto que corresponde à definição do iterador na especificação. Seu nextmétodo retorna um novo objeto de resultado toda vez que você o chama. O objeto de resultado possui uma propriedade, doneinformando se foi concluída, e uma propriedade valuecom o valor dessa iteração. ( doneé opcional se for false, valueé opcional se for undefined.)
O significado de valuevaria dependendo do iterador; matrizes suportam (pelo menos) três funções que retornam iteradores:
values(): Este é o que eu usei acima. Devolve uma iteração, onde cada um valueé a entrada da matriz para a iteração ( "a", "b", e "c"no exemplo anterior).
keys(): Retorna um iterador onde cada valueé a chave para a iteração (assim para o nosso aacima, que seria "0", então "1", a seguir "2").
entries(): Retorna um iterador em que cada valueum é uma matriz no formulário [key, value]para essa iteração.
Para objetos semelhantes a matrizes
Além de matrizes verdadeiras, também existem objetos semelhantes a matrizes que possuem uma lengthpropriedade e propriedades com nomes numéricos: NodeListinstâncias, argumentsobjeto, etc. Como percorrer o conteúdo deles?
Use qualquer uma das opções acima para matrizes
Pelo menos algumas das abordagens de matriz acima, e possivelmente a maioria ou mesmo todas, se aplicam com freqüência igualmente bem a objetos do tipo matriz:
Uso forEache afins (ES5 +)
As várias funções ativadas Array.prototypesão "intencionalmente genéricas" e geralmente podem ser usadas em objetos do tipo array via Function#callou Function#apply. (Consulte a Advertência para obter os objetos fornecidos pelo host no final desta resposta, mas é um problema raro.)
Suponha que você queira usar forEachem um Node's childNodespropriedade. Você faria isso:
Array.prototype.forEach.call(node.childNodes,function(child){// Do something with `child`});
Se você fizer muito isso, convém pegar uma cópia da referência de função em uma variável para reutilização, por exemplo:
// (This is all presumably in some scoping function)var forEach =Array.prototype.forEach;// Then later...
forEach.call(node.childNodes,function(child){// Do something with `child`});
Use um forloop simples
Obviamente, um forloop simples se aplica a objetos do tipo array.
Use for-incorretamente
for-incom as mesmas salvaguardas que uma matriz, também deve funcionar com objetos semelhantes a matrizes; a ressalva para os objetos fornecidos pelo host em # 1 acima pode ser aplicada.
Use for-of(use um iterador implicitamente) (ES2015 +)
for-ofusa o iterador fornecido pelo objeto (se houver). Isso inclui objetos fornecidos pelo host. Por exemplo, a especificação para NodeListfrom querySelectorAllfoi atualizada para suportar a iteração. A especificação para o HTMLCollectionde getElementsByTagNamenão era.
Use um iterador explicitamente (ES2015 +)
Veja # 4.
Crie uma matriz verdadeira
Outras vezes, convém converter um objeto semelhante a uma matriz em uma matriz verdadeira. Fazer isso é surpreendentemente fácil:
Use o slicemétodo de matrizes
Podemos usar o slicemétodo de matrizes, que, como os outros métodos mencionados acima, é "intencionalmente genérico" e, portanto, pode ser usado com objetos semelhantes a matrizes, assim:
var trueArray =Array.prototype.slice.call(arrayLikeObject);
Por exemplo, se quisermos converter um NodeListem um array verdadeiro, poderíamos fazer isso:
var divs =Array.prototype.slice.call(document.querySelectorAll("div"));
Veja a Advertência para obter os objetos fornecidos pelo host abaixo. Em particular, observe que isso falhará no IE8 e versões anteriores, o que não permite que você use objetos fornecidos pelo host thisdessa maneira.
Usar sintaxe de propagação ( ...)
Também é possível usar a sintaxe de propagação do ES2015 com mecanismos JavaScript compatíveis com esse recurso. Assim for-of, isso usa o iterador fornecido pelo objeto (consulte o item 4 na seção anterior):
var trueArray =[...iterableObject];
Por exemplo, se queremos converter um NodeListem um array verdadeiro, com a sintaxe espalhada, isso se torna bastante sucinto:
var divs =[...document.querySelectorAll("div")];
Usar Array.from
Array.from(especificação) | (MDN) (ES2015 +, mas facilmente preenchido com polifólio) cria uma matriz a partir de um objeto semelhante a uma matriz, passando opcionalmente as entradas por meio de uma função de mapeamento. Assim:
var divs =Array.from(document.querySelectorAll("div"));
Ou, se você deseja obter uma matriz dos nomes de tags dos elementos com uma determinada classe, use a função de mapeamento:
// Arrow function (ES2015):var divs =Array.from(document.querySelectorAll(".some-class"), element => element.tagName);// Standard function (since `Array.from` can be shimmed):var divs =Array.from(document.querySelectorAll(".some-class"),function(element){return element.tagName;});
Advertência para objetos fornecidos pelo host
Se você usar Array.prototypefunções com objetos do tipo matriz fornecidos pelo host (listas DOM e outras coisas fornecidas pelo navegador em vez do mecanismo JavaScript), será necessário testar nos ambientes de destino para garantir que o objeto fornecido pelo host se comporte corretamente . A maioria se comporta corretamente (agora), mas é importante testar. O motivo é que a maioria dos Array.prototypemétodos que você provavelmente deseja usar depende do objeto fornecido pelo host, fornecendo uma resposta honesta à [[HasProperty]]operação abstrata . No momento da redação deste artigo, os navegadores fazem um bom trabalho, mas a especificação 5.1 permitiu a possibilidade de um objeto fornecido pelo host não ser honesto. Está no §8.6.2 , vários parágrafos abaixo da tabela grande perto do início dessa seção), onde diz:
Os objetos host podem implementar esses métodos internos de qualquer maneira, a menos que especificado de outra forma; por exemplo, uma possibilidade é que [[Get]]e [[Put]]para um objeto de host específico, de fato buscar e armazenar valores de propriedade, mas [[HasProperty]]sempre gera falsa .
(Eu não poderia encontrar o palavreado equivalente no ES2015 spec, mas é obrigado a continuar a ser o caso.) Mais uma vez, como esta escrito o comum matriz como objetos em navegadores modernos [fornecido pelo anfitrião NodeListcasos, por exemplo] fazer alça [[HasProperty]]corretamente, mas é importante testar.)
Eu também gostaria de acrescentar que .forEachnão pode ser quebrado com eficiência. Você precisa lançar uma exceção para executar o intervalo.
Pijusn
82
@ Pius: Se você quiser quebrar o loop, pode usar some. (Eu teria preferido permitindo quebra forEachbem, mas, hum, não me pergunte ;-).)
TJ Crowder
6
@TJCrowder True, mesmo que pareça mais uma solução alternativa, pois não é seu objetivo principal.
Pijusn
8
@ user889030: Você precisa de um ,depois k=0, não um ;. Lembre-se, a programação é muitas coisas, uma das quais é muita atenção aos detalhes ... :-)
TJ Crowder
5
@ JimB: Isso é coberto acima (e lengthnão é um método). :-)
TJ Crowder
513
Nota : Esta resposta está irremediavelmente desatualizada. Para uma abordagem mais moderna, observe os métodos disponíveis em uma matriz . Os métodos de interesse podem ser:
para cada
mapa
filtro
fecho eclair
reduzir
cada
alguns
A maneira padrão de iterar uma matriz em JavaScript é um forloop de baunilha :
var length = arr.length,
element =null;for(var i =0; i < length; i++){
element = arr[i];// Do something with element}
Observe, no entanto, que essa abordagem só é boa se você tiver uma matriz densa e cada índice for ocupado por um elemento. Se a matriz for escassa, você poderá ter problemas de desempenho com essa abordagem, pois iterará em muitos índices que realmente não existem na matriz. Nesse caso, um for .. inloop pode ser uma ideia melhor. No entanto , você deve usar as salvaguardas apropriadas para garantir que apenas as propriedades desejadas da matriz (ou seja, os elementos da matriz) sejam acionadas, pois o for..inloop também será enumerado em navegadores herdados ou se as propriedades adicionais forem definidas como enumerable.
No ECMAScript 5 , haverá um método forEach no protótipo da matriz, mas ele não é suportado em navegadores herdados. Para poder usá-lo consistentemente, você deve ter um ambiente que o suporte (por exemplo, Node.js para JavaScript no servidor) ou usar um "Polyfill". O Polyfill para essa funcionalidade é, no entanto, trivial e, como facilita a leitura do código, é um bom polyfill a ser incluído.
por que for(instance in objArray) não é um uso correto? parece mais simples para mim, mas eu ouvi você falar disso como uma maneira incorreta de uso?
Dante1986
21
Você pode usar o cache de comprimento em linha: for (var i = 0, l = arr.Length; i <l; i ++)
Robert Hoffmann
3
A vírgula no final da primeira linha é intencional ou é um erro de digitação (pode ser ponto-e-vírgula)?
Mohd Abdul Mujib
6
@ wardha-Web É intencional. Ele nos permite declarar várias variáveis com uma única varpalavra-chave. Se tivéssemos usado um ponto-e-vírgula, elementteríamos sido declarados no escopo global (ou melhor, o JSHint teria gritado conosco antes de atingir a produção).
PatrikAkerstrand
239
Se você estiver usando a biblioteca jQuery , poderá usar o jQuery.each :
$.each(yourArray,function(index, value){// do your stuff here});
EDIT:
Conforme a pergunta, o usuário deseja código em javascript, em vez de jquery, para que a edição seja
var length = yourArray.length;for(var i =0; i < length; i++){// Do something with yourArray[i].}
Provavelmente vou usar essa resposta com mais frequência. Não é a melhor resposta para a pergunta, mas na prática será a mais simples e a mais aplicável para aqueles que usam o jQuery. Eu acho que todos nós devemos aprender o caminho da baunilha também. Nunca é demais expandir sua compreensão.
mopsyd
47
Por uma questão de segurança: o jQuery é cada vez mais lento que as soluções nativas. É recomendado pelo jQuery usar JavaScript nativo em vez do jQuery sempre que possível. jsperf.com/browser-diet-jquery-each-vs-for-loop
Kevin Boss
8
Abster-se de usar jQuery quando você pode usar vanilla js
Noe
2
Vara para JS padrão, manter a 3ª bibliotecas de fora da resposta a menos que não é uma solução língua nativa
scubasteve
116
Loop para trás
Eu acho que o inverso laço for merece uma menção aqui:
for(var i = array.length; i--;){// process array[i]}
Vantagens:
Você não precisa declarar uma lenvariável temporária ou comparar array.lengthem cada iteração, uma das quais pode ser uma otimização minuciosa.
Remover irmãos do DOM na ordem inversa geralmente é mais eficiente . (O navegador precisa fazer menos deslocamentos de elementos em suas matrizes internas.)
Se você modificar a matriz enquanto faz o loop, no ou após o índice i (por exemplo, você remove ou insere um item em array[i]), um loop para frente ignora o item que foi deixado na posição i ou processa novamente o i- ésimo item mudou para a direita. Em um loop for tradicional, você pode atualizar i para apontar para o próximo item que precisa ser processado - 1, mas simplesmente reverter a direção da iteração geralmente é uma solução mais simples e elegante .
Da mesma forma, ao modificar ou remover elementos DOM aninhados , o processamento inverso pode contornar erros . Por exemplo, considere modificar o innerHTML de um nó pai antes de manipular seus filhos. Quando o nó filho for alcançado, ele será desconectado do DOM, tendo sido substituído por um filho recém-criado quando o innerHTML do pai foi gravado.
É mais curto para digitar e ler do que algumas das outras opções disponíveis. Embora perca para forEach()e para ES6 for ... of.
Desvantagens:
Ele processa os itens na ordem inversa. Se você estava criando uma nova matriz a partir dos resultados ou imprimindo itens na tela, naturalmente a saída será revertida em relação à ordem original.
A inserção repetida de irmãos no DOM como primeiro filho para manter seu pedido é menos eficiente . (O navegador continuaria tendo que mudar as coisas da maneira correta.) Para criar nós DOM com eficiência e ordem, faça um loop para frente e acrescente normalmente (e também use um "fragmento de documento").
O loop reverso é confuso para desenvolvedores juniores. (Você pode considerar isso uma vantagem, dependendo da sua perspectiva.)
Devo sempre usá-lo?
Alguns desenvolvedores usam o loop for reverso por padrão , a menos que haja uma boa razão para fazer o loop forward.
Embora os ganhos de desempenho sejam geralmente insignificantes, isso meio que grita:
"Basta fazer isso com todos os itens da lista, não me importo com o pedido!"
No entanto, na prática, que é não realmente uma indicação confiável de intenções, uma vez que é indistinguível aquelas ocasiões quando você fazer o cuidado sobre a ordem, e realmente necessidade para repetir em sentido inverso. Portanto, de fato, seria necessário outro construto para expressar com precisão a intenção "não me importo", algo atualmente indisponível na maioria dos idiomas, incluindo ECMAScript, mas que pode ser chamado, por exemplo forEachUnordered(),.
Se a ordem não importa e a eficiência é uma preocupação (no loop mais interno de um mecanismo de jogo ou de animação), pode ser aceitável usar o loop for reverso como seu padrão inicial. Lembre-se de que ver um loop for reverso no código existente não significa necessariamente que a ordem seja irrelevante!
Era melhor usar forEach ()
Em geral, para códigos de nível superior, onde a clareza e a segurança são preocupações maiores, eu já recomendei usar Array::forEachcomo padrão padrão para loop (embora hoje em dia eu prefira usar for..of). Os motivos para preferir forEachum loop reverso são:
É mais claro de ler.
Isso indica que eu não vou ser deslocado dentro do bloco (o que é sempre uma possível surpresa escondida em longas fore whilevoltas).
Dá a você um espaço livre para fechamentos.
Reduz o vazamento de variáveis locais e a colisão acidental com (e mutação) de variáveis externas.
Então, quando você vê o loop for reverso no seu código, é uma dica de que ele é revertido por um bom motivo (talvez um dos motivos descritos acima). E ver um loop for forward tradicional pode indicar que a mudança pode ocorrer.
(Se a discussão sobre intenção não faz sentido para você, você e seu código podem se beneficiar assistindo a palestra de Crockford sobre Estilo de programação e seu cérebro .)
Agora é ainda melhor usar para ... de!
Há um debate sobre se é for..ofou forEach()não preferível:
Para obter o máximo suporte do navegador, é for..ofnecessário um polyfill para iteradores, tornando o aplicativo um pouco mais lento para executar e um pouco maior para baixar.
Pessoalmente, costumo usar o que parecer mais fácil de ler, a menos que desempenho ou minificação se tornem uma grande preocupação. Portanto, hoje em dia eu prefiro usar em for..ofvez de forEach(), mas sempre usarei mapou filterou findou somequando aplicável. (Pelo bem de meus colegas, eu raramente uso reduce.)
Como funciona?
for(var i =0; i < array.length; i++){...}// Forwardsfor(var i = array.length; i--;){...}// Reverse
Você notará que essa i--é a cláusula do meio (onde geralmente vemos uma comparação) e a última cláusula está vazia (onde geralmente vemos i++). Isso significa que i--também é usado como condição para continuação. Fundamentalmente, é executado e verificado antes de cada iteração.
Como pode começar array.lengthsem explodir?
Como i--é executado antes de cada iteração, na primeira iteração, estaremos acessando o item no array.length - 1qual evita qualquer problema com os itens da matriz fora dos limitesundefined .
Por que ele não para de iterar antes do índice 0?
O loop interromperá a iteração quando a condição for i--avaliada como um valor de falsey (quando produzir 0).
O truque é que --i, diferentemente , o i--operador à direita diminui, imas gera o valor antes da diminuição. Seu console pode demonstrar isso:
> var i = 5; [i, i--, i];
[5, 5, 4]
Portanto, na iteração final, eu era anteriormente 1 e a i--expressão o altera para 0, mas na verdade produz 1 ( verdade ) e, portanto, a condição passa. Na próxima iteração i--muda i a -1 , mas gera 0 (Falsey), fazendo com que a execução a cair imediatamente para fora da parte inferior do circuito.
Nos tradicionais forward for loop, i++e ++isão intercambiáveis (como Douglas Crockford aponta). No entanto, no loop for reverso, porque nosso decréscimo também é nossa expressão de condição, devemos permanecer com i--se queremos processar o item no índice 0.
Curiosidades
Algumas pessoas gostam de desenhar uma flecha no forloop reverso e terminam com uma piscadela:
for(var i = array.length; i -->0;){
Os créditos vão para a JMJ por me mostrar os benefícios e os horrores do inverso do loop.
Eu esqueci de adicionar os benchmarks . Também esqueci de mencionar como o loop reverso é uma otimização significativa em processadores de 8 bits como o 6502, onde você realmente faz a comparação de graça!
Joeytwiddle
A mesma resposta é dada de forma muito mais concisa aqui (em uma pergunta diferente).
var index,
value;for(index in obj){
value = obj[index];}
Há um problema. for..inpercorrerá cada um dos membros enumeráveis do objeto e os membros em seu protótipo. Para evitar a leitura de valores herdados pelo protótipo do objeto, basta verificar se a propriedade pertence ao objeto:
for(i in obj){if(obj.hasOwnProperty(i)){//do stuff}}
Além disso, o ECMAScript 5 adicionou um forEachmétodo ao Array.prototypequal pode ser usado para enumerar em uma matriz usando um calback (o polyfill está nos documentos para que você ainda possa usá-lo em navegadores mais antigos):
É importante observar que Array.prototype.forEachnão é interrompido quando o retorno de chamada retorna false. O jQuery e o Underscore.js fornecem suas próprias variações eachpara fornecer loops que podem sofrer um curto-circuito.
Então, como é possível sair de um loop foreach do ECMAScript5 como faria em um loop for for normal ou em um loop foreach como o encontrado em linguagens no estilo C?
Ciaran Gallagher 03/03
5
@CiaranG, em JavaScript, é comum ver eachmétodos que permitem return falseser usados para romper o ciclo, mas com forEachisso não é uma opção. Uma bandeira externo poderia ser usado (ie if (flag) return;, mas só impediria o resto do corpo da função de execução, forEachseria ainda continuam iteração sobre a coleção inteira.
zzzzBov
43
Se você deseja fazer um loop sobre uma matriz, use o forloop de três partes padrão .
for(var i =0; i < myArray.length; i++){var arrayItem = myArray[i];}
Você pode obter algumas otimizações de desempenho armazenando em cache myArray.lengthou iterando-o para trás.
for (var i = 0, comprimento = myArray.length; i <comprimento; i ++) deve fazê-lo
Edson Medina
5
@ EdsonMedina Isso também criará uma nova variável global chamada length. ;)
joeytwiddle
4
@joeytwiddle Sim, mas isso está além do escopo deste post. Você criará uma variável global i de qualquer maneira.
Edson Medina
6
@EdsonMedina Minhas desculpas, eu estava completamente errado. O uso ,após uma tarefa não apresenta uma nova global, portanto, sua sugestão é ótima ! Eu estava confundindo isso com um problema diferente: o uso =após uma atribuição cria uma nova global.
Joeytwiddle
Cuidado variável i não é local para o loop. JavaScript não tem escopo de bloco. Provavelmente é melhor declarar var i, length, arrayItem;antes do loop para evitar esse mal-entendido.
James
35
Eu sei que este é um post antigo, e já existem muitas ótimas respostas. Para um pouco mais de completude, imaginei que jogaria outro usando o AngularJS . Obviamente, isso só se aplica se você estiver usando Angular, obviamente, no entanto, eu gostaria de colocar de qualquer maneira.
angular.forEachleva 2 argumentos e um terceiro argumento opcional. O primeiro argumento é o objeto (matriz) a ser repetido, o segundo argumento é a função iteradora e o terceiro argumento opcional é o contexto do objeto (basicamente referido dentro do loop como 'this').
Existem diferentes maneiras de usar o loop forEach de angular. O mais simples e provavelmente o mais usado é
var temp =[1,2,3];
angular.forEach(temp,function(item){//item will be each element in the array//do something});
Outra maneira útil para copiar itens de uma matriz para outra é
var temp =[1,2,3];var temp2 =[];
angular.forEach(temp,function(item){this.push(item);//"this" refers to the array passed into the optional third parameter so, in this case, temp2.}, temp2);
No entanto, você não precisa fazer isso, basta fazer o seguinte e é equivalente ao exemplo anterior:
Agora, existem prós e contras de usar a angular.forEachfunção em oposição ao forloop com sabor de baunilha .
Prós
Legibilidade fácil
Gravação fácil
Se disponível, angular.forEachusará o loop ES5 forEach. Agora, chegarei à eficiência na seção contras, pois os loops forEach são muito mais lentos que os loops for. Menciono isso como profissional, porque é bom ser consistente e padronizado.
Considere os 2 loops aninhados a seguir, que fazem exatamente a mesma coisa. Digamos que temos 2 matrizes de objetos e cada objeto contém uma matriz de resultados, cada um com uma propriedade Value que é uma string (ou qualquer outra coisa). Digamos que precisamos iterar sobre cada um dos resultados e, se forem iguais, execute alguma ação:
angular.forEach(obj1.results,function(result1){
angular.forEach(obj2.results,function(result2){if(result1.Value=== result2.Value){//do something}});});//exact same with a for loopfor(var i =0; i < obj1.results.length; i++){for(var j =0; j < obj2.results.length; j++){if(obj1.results[i].Value=== obj2.results[j].Value){//do something}}}
Concedido que este é um exemplo hipotético muito simples, mas escrevi triplamente incorporado para loops usando a segunda abordagem e foi muito difícil de ler e escrever para esse assunto.
Contras
Eficiência. angular.forEach, e o nativo forEach, aliás, são muito mais lentos que o forloop normal ... cerca de 90% mais lento . Portanto, para conjuntos de dados grandes, é melhor manter o forloop nativo .
Sem interrupção, continue ou devolva o suporte. continueé realmente suportado por " acidente ", para continuar com uma angular.forEachsimples return;instrução na função, o angular.forEach(array, function(item) { if (someConditionIsTrue) return; });que fará com que ela continue fora da função para essa iteração. Isso também se deve ao fato de o nativo forEachnão suportar interrupção ou continuar.
Tenho certeza de que existem vários outros prós e contras também, e fique à vontade para adicionar os que achar melhor. Eu acho que, se você precisar de eficiência, use apenas o forloop nativo para suas necessidades de loop. Mas, se os seus conjuntos de dados são menores e é conveniente desistir de alguma eficiência em troca da legibilidade e da capacidade de gravação, então, de todas as maneiras, jogue um pouco angular.forEachnaquele garoto mau.
function forEach(list,callback){var length = list.length;for(var n =0; n < length; n++){
callback.call(list[n]);}}var myArray =['hello','world'];
forEach(
myArray,function(){
alert(this);// do something});
Provavelmente o for(i = 0; i < array.length; i++)loop não é a melhor escolha. Por quê? Se você tem isso:
var array =newArray();
array[1]="Hello";
array[7]="World";
array[11]="!";
O método chamará de array[0]para array[2]. Primeiro, isso fará referência a variáveis que você nem sequer tem, depois não terá as variáveis na matriz e, terceiro, tornará o código em negrito. Olha aqui, é o que eu uso:
for(var i in array){var el = array[i];//If you want 'i' to be INT just put parseInt(i)//Do something with el}
E se você quiser que seja uma função, você pode fazer isso:
function foreach(array, call){for(var i in array){
call(array[i]);}}
Se você quiser quebrar, um pouco mais de lógica:
function foreach(array, call){for(var i in array){if(call(array[i])==false){break;}}}
Existem três implementações foreachno jQuery da seguinte maneira.
var a =[3,2];
$(a).each(function(){console.log(this.valueOf())});//Method 1
$.each(a,function(){console.log(this.valueOf())});//Method 2
$.each($(a),function(){console.log(this.valueOf())});//Method 3
Onde of evita as esquisitices associadas ine faz com que funcione como o forloop de qualquer outra linguagem, e letvincula - se iao loop em oposição à função.
As chaves ( {}) podem ser omitidas quando há apenas um comando (por exemplo, no exemplo acima).
Uma solução fácil agora seria usar a biblioteca underscore.js . Ele fornece muitas ferramentas úteis, como eache delegará automaticamente o trabalho para o nativoforEach se disponível.
Não há nenhum for eachloop no JavaScript nativo . Você pode usar bibliotecas para obter essa funcionalidade (eu recomendo o Underscore.js ), use um forloop simples .
Este é um iterador para lista NÃO esparsa, onde o índice começa em 0, que é o cenário típico ao lidar com document.getElementsByTagName ou document.querySelectorAll)
function each( fn, data ){if(typeof fn =='string')eval('fn = function(data, i){'+ fn +'}');for(var i=0, L=this.length; i < L; i++)
fn.call(this[i], data, i );returnthis;}Array.prototype.each = each;
Exemplos de uso:
Exemplo 1
var arr =[];[1,2,3].each(function(a){ a.push(this*this}, arr);
arr =[1,4,9]
each.call(document.getElementsByTagName('p'),"if( i % 2 == 0) this.className = data;",'red');
Qualquer outra tag p recebe class="red">
Exemplo 4
each.call(document.querySelectorAll('p.blue'),function(newClass, i){if( i <20)this.className = newClass;},'green');
E, finalmente, as 20 primeiras tags p azuis são alteradas para verde
Cuidado ao usar string como função: a função é criada fora do contexto e deve ser usada apenas quando você tiver certeza do escopo da variável. Caso contrário, é melhor passar funções nas quais o escopo é mais intuitivo.
Existem algumas maneiras de percorrer uma matriz em JavaScript, como abaixo:
para - é o mais comum . Bloco de código completo para loop
var languages =["Java","JavaScript","C#","Python"];var i, len, text;for(i =0, len = languages.length, text =""; i < len; i++){
text += languages[i]+"<br>";}
document.getElementById("example").innerHTML = text;
Laços funcionais - forEach, map, filter, também reduce(eles percorrer a função, mas eles são usados se você precisa fazer alguma coisa com sua matriz, etc.
// For example, in this case we loop through the number and double them up using the map functionvar numbers =[65,44,12,4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num *2});
Correção pequena: forEachnão é um loop "funcional", pois não retorna um novo Array(na verdade, não retorna nada), apenas itera.
Nicholaswmin
19
ECMAScript 5 (a versão em JavaScript) para trabalhar com matrizes:
forEach - repete todos os itens da matriz e faz o que for necessário com cada item.
['C','D','E'].forEach(function(element, index){
console.log(element +" is #"+(index+1)+" in the musical scale");});// Output// C is the #1 in musical scale// D is the #2 in musical scale// E is the #3 in musical scale
No caso, mais interessado na operação em array usando algum recurso embutido.
map - Cria uma nova matriz com o resultado da função de retorno de chamada. Esse método é bom para ser usado quando você precisar formatar os elementos da sua matriz.
// Let's upper case the items in the array['bob','joe','jen'].map(function(elem){return elem.toUpperCase();});// Output: ['BOB', 'JOE', 'JEN']
reduzir - como o nome diz, reduz a matriz para um único valor, chamando a função fornecida que passa no elemento atual e o resultado da execução anterior.
Não há capacidade embutida para invadir forEach. Para interromper a execução, use o Array#someseguinte abaixo:
[1,2,3].some(function(number){return number ===1;});
Isso funciona porque someretorna true assim que qualquer retorno de chamada, executado em ordem de matriz, retorna true, causando um curto-circuito na execução do restante.
Resposta original,
consulte Protótipo de matriz para alguns
Eu também gostaria de adicionar isso como uma composição de um loop reverso e uma resposta acima para alguém que também gostaria dessa sintaxe.
var foo =[object,object,object];for(var i = foo.length, item; item = foo[--i];){
console.log(item);}
Prós:
O benefício disso: você já tem a referência no primeiro, assim não precisará ser declarada posteriormente com outra linha. É útil ao fazer um loop pela matriz de objetos.
Contras:
Isso será interrompido sempre que a referência for falsa - falsey (indefinida, etc.). Pode ser usado como uma vantagem. No entanto, tornaria um pouco mais difícil de ler. E também, dependendo do navegador, pode "não" ser otimizado para funcionar mais rápido que o original.
A reestruturação e o uso do operador de propagação se mostraram bastante úteis para os iniciantes no ECMAScript 6 como sendo mais legíveis / estéticas, embora alguns veteranos em JavaScript possam considerá-lo confuso. Os juniores ou outras pessoas podem achar útil.
Os exemplos a seguir usarão a for...ofinstrução e o.forEach método
Os exemplos 6, 7 e 8 podem ser usados com quaisquer loops funcionais, como.map , .filter, .reduce, .sort, .every, .some. Para obter mais informações sobre esses métodos, consulte o objeto Array .
Exemplo 1:for...of Loop normal - não há truques aqui.
let arrSimple =['a','b','c'];for(let letter of arrSimple){
console.log(letter);}
let arrFruits =['apple','orange','banana'];for(let[firstLetter,...restOfTheWord]of arrFruits){// Create a shallow copy using the spread operatorlet[lastLetter]=[...restOfTheWord].reverse();
console.log(firstLetter, lastLetter, restOfTheWord);}
// let arrSimple = ['a', 'b', 'c'];// Instead of keeping an index in `i` as per example `for(let i = 0 ; i<arrSimple.length;i++)`// this example will use a multi-dimensional array of the following format type:// `arrWithIndex: [number, string][]`let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Same thing can be achieved using `.map` method// let arrWithIndex = arrSimple.map((i, idx) => [idx, i]);// Same thing can be achieved using `Object.entries`// NOTE: `Object.entries` method doesn't work on Internet Explorer unless it's polyfilled// let arrWithIndex = Object.entries(arrSimple);for(let[key, value]of arrWithIndex){
console.log(key, value);}
let arrWithIndex =[[0,'a'],[1,'b'],[2,'c'],];// Not to be confused here, `forEachIndex` is the real index// `mappedIndex` was created by "another user", so you can't really trust it
arrWithIndex.forEach(([mappedIndex, item], forEachIndex)=>{
console.log(forEachIndex, mappedIndex, item);});
let arrWithObjects =[{
name:'Jon',
age:32},{
name:'Elise',
age:33}];// NOTE: Destructuring objects while using shorthand functions// are required to be surrounded by parentheses
arrWithObjects.forEach(({ name, age: aliasForAge })=>{
console.log(name, aliasForAge)});
Uma maneira mais próxima da sua idéia seria usar o Array.forEach()que aceita uma função de fechamento que será executada para cada elemento da matriz.
myArray.forEach((item)=>{// Do something
console.log(item);});
Outra maneira viável seria usar o Array.map()que funciona da mesma maneira, mas também pega todos os valores retornados e os retorna em uma nova matriz (essencialmente mapeando cada elemento para um novo), assim:
Isso está errado, mapnão modifica os elementos da matriz, pois retorna uma nova matriz, com os itens dessa nova sendo o resultado da aplicação da função aos itens da matriz antiga.
Jesus Franco
Eu nunca disse que não retorna uma nova matriz, estava me referindo à alteração aplicada pela função. Mas aqui vou mudar na resposta.
Ante Jablan Adamović 04/04/19
novamente errado, o mapa não modifica ou sofre mutação em todos os itens da matriz original, propus e editei a resposta enfatizando que o mapa funciona com uma cópia dos itens originais, deixando a matriz original inalterada
Jesús Franco
7
Você pode ligar paraEach assim:
forEachiterará sobre a matriz que você fornecer e para cada iteração que possuir, elementque retém o valor dessa iteração. Se você precisar de um índice, poderá obter o índice atual passando io segundo parâmetro na função de retorno de chamada para forEach.
O Foreach é basicamente uma função de alta ordem, que assume outra função como parâmetro.
let theArray=[1,3,2];
theArray.forEach((element)=>{// Use the element of the array
console.log(element)}
Resultado:
132
Você também pode iterar sobre uma matriz como esta:
for(let i=0; i<theArray.length; i++){
console.log(i);// i will have the value of each index}
Se você deseja percorrer uma matriz de objetos com a função de seta:
let arr =[{name:'john', age:50},{name:'clark', age:19},{name:'mohan', age:26}];
arr.forEach((person)=>{
console.log('I am '+ person.name +' and I am '+ person.age +' old');})
A sintaxe lambda geralmente não funciona no Internet Explorer 10 ou abaixo.
Eu costumo usar o
[].forEach.call(arrayName,function(value,index){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Se você é um fã de jQuery e já possui um arquivo jQuery em execução, deve reverter as posições dos parâmetros de índice e valor
$("#ul>li").each(function(**index, value**){
console.log("value of the looped element"+ value);
console.log("index of the looped element"+ index);});
Se você tem uma matriz enorme, deve usar iteratorspara obter alguma eficiência. Iteradores são uma propriedade de determinadas coleções de JavaScript (como Map, Set, String, Array). Mesmo, for..ofusaiterator sob o capô.
Os iteradores melhoram a eficiência, permitindo que você consuma os itens de uma lista, um de cada vez, como se fossem um fluxo. O que torna um iterador especial é como ele percorre uma coleção. Outros loops precisam carregar toda a coleção antecipadamente para iterá-la, enquanto um iterador precisa conhecer apenas a posição atual na coleção.
Você acessa o item atual chamando o nextmétodo do iterador . O próximo método retornará o valueitem atual e a booleanpara indicar quando você alcançou o final da coleção. A seguir, é apresentado um exemplo de criação de um iterador a partir de uma matriz.
Transforme sua matriz regular em iterador usando um values()método como este:
const myArr =[2,3,4]let it = myArr.values();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
Hoje (2019-12-18) realizo testes no meu macOS v10.13.6 (High Sierra), no Chrome v 79.0, Safari v13.0.4 e Firefox v71.0 (64 bits) - conclusões sobre otimização (e micro-otimização que geralmente não vale a pena introduzi-lo no código porque o benefício é pequeno, mas a complexidade do código aumenta).
Parece que o tradicional for i( Aa ) é uma boa opção para escrever código rápido em todos os navegadores.
As outras soluções, como for-of( Ad ), todas no grupo C. ... geralmente são de 2 a 10 (e mais) vezes mais lentas que Aa , mas para pequenas matrizes é aceitável usá-la - por uma questão de maior clareza do código.
Os loops com comprimento de array armazenados em cache em n( Ab, Bb, Be ) são algumas vezes mais rápidos, outras não. Provavelmente, os compiladores detectam automaticamente essa situação e introduzem o cache. As diferenças de velocidade entre as versões em cache e sem cache ( Aa, Ba, Bd ) são de aproximadamente 1%, portanto, parece que a introdução né uma micro otimização .
As i--soluções semelhantes em que o loop inicia a partir do último elemento da matriz ( Ac, Bc ) geralmente são aproximadamente 30% mais lentas que as soluções avançadas - provavelmente o motivo é o modo como o cache de memória da CPU está funcionando - a leitura direta da memória é mais ideal para o cache da CPU). É recomendável NÃO UTILIZAR essas soluções.
Detalhes
Nos testes, calculamos a soma dos elementos da matriz. Realizo um teste para matrizes pequenas (10 elementos) e matrizes grandes (elementos 1M) e as divido em três grupos:
Ao iterar sobre uma matriz, geralmente queremos atingir um dos seguintes objetivos:
Queremos iterar sobre a matriz e criar uma nova matriz:
Array.prototype.map
Queremos iterar sobre a matriz e não criar uma nova matriz:
Array.prototype.forEach
for..ofciclo
Em JavaScript, existem muitas maneiras de atingir esses dois objetivos. No entanto, alguns são mais convenientes que outros. Abaixo, você encontra alguns métodos mais usados (o IMO mais conveniente) para realizar a iteração de matriz em JavaScript.
Criando nova matriz: Map
map()é uma função localizada na Array.prototypequal pode transformar todos os elementos de uma matriz e, em seguida, retorna uma nova matriz. map()toma como argumento uma função de retorno de chamada e funciona da seguinte maneira:
let arr =[1,2,3,4,5];let newArr = arr.map((element, index, array)=>{return element *2;})
console.log(arr);
console.log(newArr);
O retorno de chamada para o qual passamos map()como argumento é executado para cada elemento. Em seguida, é retornada uma matriz com o mesmo comprimento da matriz original. Nesse novo elemento da matriz, é transformada pela função de retorno de chamada passada como argumento para map().
A diferença distinta entre mape outro mecanismo de loop como forEache um for..ofloop é que mapretorna uma nova matriz e deixa intacta a matriz antiga (exceto se você a manipular explicitamente com pensamentos comosplice ).
Além disso, observe que o mapretorno de chamada da função fornece o número do índice da iteração atual como um segundo argumento. Além disso, o terceiro argumento fornece a matriz na qual mapfoi chamada? Às vezes, essas propriedades podem ser muito úteis.
Loop usando forEach
forEaché uma função localizada na Array.prototypequal assume uma função de retorno de chamada como argumento. Em seguida, ele executa essa função de retorno de chamada para todos os elementos da matriz. Ao contrário da map()função, a função forEach não retorna nada ( undefined). Por exemplo:
let arr =[1,2,3,4,5];
arr.forEach((element, index, array)=>{
console.log(element *2);if(index ===4){
console.log(array)}// index, and oldArray are provided as 2nd and 3th argument by the callback})
console.log(arr);
Assim como a mapfunção, o forEachretorno de chamada fornece o número do índice da iteração atual como um segundo argumento. Além disso, o terceiro argumento fornece a matriz na qual forEachfoi chamada?
Repita os elementos usando for..of
O for..ofloop percorre todos os elementos de uma matriz (ou qualquer outro objeto iterável). Funciona da seguinte maneira:
let arr =[1,2,3,4,5];for(let element of arr){
console.log(element *2);}
No exemplo acima, elementrepresenta um elemento do array e arré o array que queremos fazer um loop. Observe que o nome elementé arbitrário, e poderíamos ter escolhido outro nome como 'el' ou algo mais declarativo quando isso for aplicável.
Não confunda o for..inloop com o for..ofloop. for..inpercorrerá todas as propriedades enumeráveis da matriz, enquanto o for..ofloop percorrerá apenas os elementos da matriz. Por exemplo:
let arr =[1,2,3,4,5];
arr.foo ='foo';for(let element of arr){
console.log(element);}for(let element in arr){
console.log(element);}
forEach
e não apenasfor
. como afirmado, em c # era um pouco diferente, e isso me confundiu :) #i < len
ei++
pode ser feito pelo motor, em vez de pelo intérprete.)Respostas:
TL; DR
for-in
menos que você o use com salvaguardas ou pelo menos esteja ciente do motivo pelo qual ele pode morder você.Suas melhores apostas são geralmente
for-of
loop (apenas ES2015 +),Array#forEach
(spec
|MDN
) (ou seus parentessome
e similares) (somente ES5 +),for
laço antiquado ,for-in
com salvaguardas.Mas há muito mais para explorar, continue a ler ...
O JavaScript possui uma semântica poderosa para fazer loop através de matrizes e objetos semelhantes a matrizes. Dividi a resposta em duas partes: opções para matrizes genuínas e opções para coisas parecidas com matrizes , como o
arguments
objeto, outros objetos iteráveis (ES2015 +), coleções DOM e assim por diante.Observarei rapidamente que você pode usar as opções do ES2015 agora , mesmo nos mecanismos ES5, transpilando o ES2015 para o ES5. Pesquise "transpiling ES2015" / "transpiling ES6" para obter mais ...
Ok, vejamos nossas opções:
Para matrizes reais
Você tem três opções no ECMAScript 5 ("ES5"), a versão mais amplamente suportada no momento, e mais duas adicionadas no ECMAScript 2015 ("ES2015", "ES6"):
forEach
e afins (ES5 +)for
loop simplesfor-in
corretamentefor-of
(use um iterador implicitamente) (ES2015 +)Detalhes:
1. Uso
forEach
e afinsEm qualquer ambiente vagamente moderno (portanto, não no IE8) em que você tenha acesso aos
Array
recursos adicionados pelo ES5 (diretamente ou usando polyfills), você pode usarforEach
(spec
|MDN
):forEach
aceita uma função de retorno de chamada e, opcionalmente, um valor para usar comothis
ao chamar esse retorno de chamada (não usado acima). O retorno de chamada é chamado para cada entrada na matriz, em ordem, ignorando entradas inexistentes em matrizes esparsas. Embora eu tenha usado apenas um argumento acima, o retorno de chamada é chamado com três: O valor de cada entrada, o índice dessa entrada e uma referência à matriz na qual você está iterando (caso sua função ainda não a tenha útil) )A menos que você ofereça suporte a navegadores obsoletos como o IE8 (que o NetApps mostra com pouco mais de 4% de participação de mercado até o momento em que escrevemos em setembro de 2016), você pode usar felizmente
forEach
uma página da Web de uso geral sem nenhum calço. Se você precisar oferecer suporte a navegadores obsoletos,forEach
é fácil fazer o shimming / polyfilling (pesquise "es5 shim" para várias opções).forEach
tem o benefício de que você não precisa declarar variáveis de indexação e valor no escopo que contém, pois elas são fornecidas como argumentos para a função de iteração e têm um escopo adequado para essa iteração.Se você está preocupado com o custo de tempo de execução de uma chamada de função para cada entrada da matriz, não fique; detalhes .
Além disso,
forEach
é a função "loop through all all", mas o ES5 definiu várias outras funções úteis "percorrer a matriz e executar tarefas", incluindo:every
(para de repetir a primeira vez que o retorno de chamada retornafalse
ou algo está errado)some
(para de repetir a primeira vez que o retorno de chamadatrue
ou algo verdadeiro)filter
(cria uma nova matriz, incluindo elementos onde a função de filtro retornatrue
e omite os que retornamfalse
)map
(cria uma nova matriz a partir dos valores retornados pelo retorno de chamada)reduce
(cria um valor chamando repetidamente o retorno de chamada, transmitindo valores anteriores; consulte a especificação para obter detalhes; útil para resumir o conteúdo de uma matriz e muitas outras coisas)reduceRight
(comoreduce
, mas funciona em ordem decrescente em vez de crescente)2. Use um
for
loop simplesÀs vezes, os modos antigos são os melhores:
Se o comprimento da matriz não vai mudar durante o ciclo, e é em código sensível ao desempenho (improvável), uma versão um pouco mais complicado agarrando o comprimento na frente pode ser um minúsculo pouco mais rápido:
E / ou contando para trás:
Mas, com os modernos mecanismos JavaScript, é raro você precisar aproveitar esse último pedaço de suco.
No ES2015 e superior, você pode tornar suas variáveis de índice e valor locais para o
for
loop:Mostrar snippet de código
E quando você faz isso, não só
value
mas tambémindex
é recriado para cada iteração do loop, ou seja, fechamentos criados no corpo do loop manter uma referência aoindex
(evalue
) criado para a iteração específica:Mostrar snippet de código
Se você tivesse cinco divs, obteria "O índice é: 0" se você clicou no primeiro e "O índice é: 4" se você clicou no último. Isso não funciona se você usar em
var
vez delet
.3. Use
for-in
corretamenteVocê fará as pessoas dizerem para você usar
for-in
, mas nãofor-in
é para isso .for-in
percorre as propriedades enumeráveis de um objeto , não os índices de uma matriz. O pedido não é garantido , nem mesmo no ES2015 (ES6). ES2015 + faz definir uma ordem para as propriedades do objeto (via[[OwnPropertyKeys]]
,[[Enumerate]]
e as coisas que os utilizam comoObject.getOwnPropertyKeys
), mas não define quefor-in
iria seguir essa ordem; ES2020 fez, no entanto. (Detalhes nesta outra resposta .)Os únicos casos de uso reais
for-in
em uma matriz são:Observando apenas o primeiro exemplo: você pode
for-in
visitar esses elementos esparsos da matriz se usar as salvaguardas apropriadas:Observe as três verificações:
Que o objeto tem sua própria propriedade com esse nome (não herdado de seu protótipo) e
Que a chave tem todos os dígitos decimais (por exemplo, forma normal de string, não notação científica) e
Que o valor da chave quando coagido a um número é <= 2 ^ 32 - 2 (que é 4.294.967.294). De onde vem esse número? Faz parte da definição de um índice de matriz na especificação . Outros números (não inteiros, números negativos, números maiores que 2 ^ 32 - 2) não são índices de matriz. A razão é 2 ^ 32 - 2 é que faz com que o maior valor de índice um menor que 2 ^ 32 - 1 , que é o valor máximo de uma matriz
length
pode ter. (Por exemplo, o comprimento de uma matriz se encaixa em um número inteiro não assinado de 32 bits.) (Adota o RobG por apontar em um comentário no meu blog que o meu teste anterior não estava certo.)Você não faria isso em código embutido, é claro. Você escreveria uma função utilitária. Possivelmente:
Mostrar snippet de código
4. Use
for-of
(use um iterador implicitamente) (ES2015 +)O ES2015 adicionou iteradores ao JavaScript. A maneira mais fácil de usar iteradores é a nova
for-of
declaração. Se parece com isso:Sob as cobertas, ele obtém um iterador da matriz e passa por ela, obtendo os valores dela. Isso não tem o problema que usar
for-in
has, porque usa um iterador definido pelo objeto (a matriz), e as matrizes definem que seus iteradores iteram pelas entradas (não pelas propriedades). Diferentementefor-in
do ES5, a ordem na qual as entradas são visitadas é a ordem numérica de seus índices.5. Use um iterador explicitamente (ES2015 +)
Às vezes, convém usar um iterador explicitamente . Você pode fazer isso também, embora seja muito mais complicado do que isso
for-of
. Se parece com isso:O iterador é um objeto que corresponde à definição do iterador na especificação. Seu
next
método retorna um novo objeto de resultado toda vez que você o chama. O objeto de resultado possui uma propriedade,done
informando se foi concluída, e uma propriedadevalue
com o valor dessa iteração. (done
é opcional se forfalse
,value
é opcional se forundefined
.)O significado de
value
varia dependendo do iterador; matrizes suportam (pelo menos) três funções que retornam iteradores:values()
: Este é o que eu usei acima. Devolve uma iteração, onde cada umvalue
é a entrada da matriz para a iteração ("a"
,"b"
, e"c"
no exemplo anterior).keys()
: Retorna um iterador onde cadavalue
é a chave para a iteração (assim para o nossoa
acima, que seria"0"
, então"1"
, a seguir"2"
).entries()
: Retorna um iterador em que cadavalue
um é uma matriz no formulário[key, value]
para essa iteração.Para objetos semelhantes a matrizes
Além de matrizes verdadeiras, também existem objetos semelhantes a matrizes que possuem uma
length
propriedade e propriedades com nomes numéricos:NodeList
instâncias,arguments
objeto, etc. Como percorrer o conteúdo deles?Use qualquer uma das opções acima para matrizes
Pelo menos algumas das abordagens de matriz acima, e possivelmente a maioria ou mesmo todas, se aplicam com freqüência igualmente bem a objetos do tipo matriz:
Uso
forEach
e afins (ES5 +)As várias funções ativadas
Array.prototype
são "intencionalmente genéricas" e geralmente podem ser usadas em objetos do tipo array viaFunction#call
ouFunction#apply
. (Consulte a Advertência para obter os objetos fornecidos pelo host no final desta resposta, mas é um problema raro.)Suponha que você queira usar
forEach
em umNode
'schildNodes
propriedade. Você faria isso:Se você fizer muito isso, convém pegar uma cópia da referência de função em uma variável para reutilização, por exemplo:
Use um
for
loop simplesObviamente, um
for
loop simples se aplica a objetos do tipo array.Use
for-in
corretamentefor-in
com as mesmas salvaguardas que uma matriz, também deve funcionar com objetos semelhantes a matrizes; a ressalva para os objetos fornecidos pelo host em # 1 acima pode ser aplicada.Use
for-of
(use um iterador implicitamente) (ES2015 +)for-of
usa o iterador fornecido pelo objeto (se houver). Isso inclui objetos fornecidos pelo host. Por exemplo, a especificação paraNodeList
fromquerySelectorAll
foi atualizada para suportar a iteração. A especificação para oHTMLCollection
degetElementsByTagName
não era.Use um iterador explicitamente (ES2015 +)
Veja # 4.
Crie uma matriz verdadeira
Outras vezes, convém converter um objeto semelhante a uma matriz em uma matriz verdadeira. Fazer isso é surpreendentemente fácil:
Use o
slice
método de matrizesPodemos usar o
slice
método de matrizes, que, como os outros métodos mencionados acima, é "intencionalmente genérico" e, portanto, pode ser usado com objetos semelhantes a matrizes, assim:Por exemplo, se quisermos converter um
NodeList
em um array verdadeiro, poderíamos fazer isso:Veja a Advertência para obter os objetos fornecidos pelo host abaixo. Em particular, observe que isso falhará no IE8 e versões anteriores, o que não permite que você use objetos fornecidos pelo host
this
dessa maneira.Usar sintaxe de propagação (
...
)Também é possível usar a sintaxe de propagação do ES2015 com mecanismos JavaScript compatíveis com esse recurso. Assim
for-of
, isso usa o iterador fornecido pelo objeto (consulte o item 4 na seção anterior):Por exemplo, se queremos converter um
NodeList
em um array verdadeiro, com a sintaxe espalhada, isso se torna bastante sucinto:Usar
Array.from
Array.from
(especificação) | (MDN) (ES2015 +, mas facilmente preenchido com polifólio) cria uma matriz a partir de um objeto semelhante a uma matriz, passando opcionalmente as entradas por meio de uma função de mapeamento. Assim:Ou, se você deseja obter uma matriz dos nomes de tags dos elementos com uma determinada classe, use a função de mapeamento:
Advertência para objetos fornecidos pelo host
Se você usar
Array.prototype
funções com objetos do tipo matriz fornecidos pelo host (listas DOM e outras coisas fornecidas pelo navegador em vez do mecanismo JavaScript), será necessário testar nos ambientes de destino para garantir que o objeto fornecido pelo host se comporte corretamente . A maioria se comporta corretamente (agora), mas é importante testar. O motivo é que a maioria dosArray.prototype
métodos que você provavelmente deseja usar depende do objeto fornecido pelo host, fornecendo uma resposta honesta à[[HasProperty]]
operação abstrata . No momento da redação deste artigo, os navegadores fazem um bom trabalho, mas a especificação 5.1 permitiu a possibilidade de um objeto fornecido pelo host não ser honesto. Está no §8.6.2 , vários parágrafos abaixo da tabela grande perto do início dessa seção), onde diz:(Eu não poderia encontrar o palavreado equivalente no ES2015 spec, mas é obrigado a continuar a ser o caso.) Mais uma vez, como esta escrito o comum matriz como objetos em navegadores modernos [fornecido pelo anfitrião
NodeList
casos, por exemplo] fazer alça[[HasProperty]]
corretamente, mas é importante testar.)fonte
.forEach
não pode ser quebrado com eficiência. Você precisa lançar uma exceção para executar o intervalo.some
. (Eu teria preferido permitindo quebraforEach
bem, mas, hum, não me pergunte ;-).),
depoisk=0
, não um;
. Lembre-se, a programação é muitas coisas, uma das quais é muita atenção aos detalhes ... :-)length
não é um método). :-)Nota : Esta resposta está irremediavelmente desatualizada. Para uma abordagem mais moderna, observe os métodos disponíveis em uma matriz . Os métodos de interesse podem ser:
A maneira padrão de iterar uma matriz em JavaScript é um
for
loop de baunilha :Observe, no entanto, que essa abordagem só é boa se você tiver uma matriz densa e cada índice for ocupado por um elemento. Se a matriz for escassa, você poderá ter problemas de desempenho com essa abordagem, pois iterará em muitos índices que realmente não existem na matriz. Nesse caso, um
for .. in
loop pode ser uma ideia melhor. No entanto , você deve usar as salvaguardas apropriadas para garantir que apenas as propriedades desejadas da matriz (ou seja, os elementos da matriz) sejam acionadas, pois ofor..in
loop também será enumerado em navegadores herdados ou se as propriedades adicionais forem definidas comoenumerable
.No ECMAScript 5 , haverá um método forEach no protótipo da matriz, mas ele não é suportado em navegadores herdados. Para poder usá-lo consistentemente, você deve ter um ambiente que o suporte (por exemplo, Node.js para JavaScript no servidor) ou usar um "Polyfill". O Polyfill para essa funcionalidade é, no entanto, trivial e, como facilita a leitura do código, é um bom polyfill a ser incluído.
fonte
for(instance in objArray)
não é um uso correto? parece mais simples para mim, mas eu ouvi você falar disso como uma maneira incorreta de uso?var
palavra-chave. Se tivéssemos usado um ponto-e-vírgula,element
teríamos sido declarados no escopo global (ou melhor, o JSHint teria gritado conosco antes de atingir a produção).Se você estiver usando a biblioteca jQuery , poderá usar o jQuery.each :
EDIT:
Conforme a pergunta, o usuário deseja código em javascript, em vez de jquery, para que a edição seja
fonte
Loop para trás
Eu acho que o inverso laço for merece uma menção aqui:
Vantagens:
len
variável temporária ou comparararray.length
em cada iteração, uma das quais pode ser uma otimização minuciosa.array[i]
), um loop para frente ignora o item que foi deixado na posição i ou processa novamente o i- ésimo item mudou para a direita. Em um loop for tradicional, você pode atualizar i para apontar para o próximo item que precisa ser processado - 1, mas simplesmente reverter a direção da iteração geralmente é uma solução mais simples e elegante .forEach()
e para ES6for ... of
.Desvantagens:
Devo sempre usá-lo?
Alguns desenvolvedores usam o loop for reverso por padrão , a menos que haja uma boa razão para fazer o loop forward.
Embora os ganhos de desempenho sejam geralmente insignificantes, isso meio que grita:
No entanto, na prática, que é não realmente uma indicação confiável de intenções, uma vez que é indistinguível aquelas ocasiões quando você fazer o cuidado sobre a ordem, e realmente necessidade para repetir em sentido inverso. Portanto, de fato, seria necessário outro construto para expressar com precisão a intenção "não me importo", algo atualmente indisponível na maioria dos idiomas, incluindo ECMAScript, mas que pode ser chamado, por exemplo
forEachUnordered()
,.Se a ordem não importa e a eficiência é uma preocupação (no loop mais interno de um mecanismo de jogo ou de animação), pode ser aceitável usar o loop for reverso como seu padrão inicial. Lembre-se de que ver um loop for reverso no código existente não significa necessariamente que a ordem seja irrelevante!
Era melhor usar forEach ()
Em geral, para códigos de nível superior, onde a clareza e a segurança são preocupações maiores, eu já recomendei usar
Array::forEach
como padrão padrão para loop (embora hoje em dia eu prefira usarfor..of
). Os motivos para preferirforEach
um loop reverso são:for
ewhile
voltas).Então, quando você vê o loop for reverso no seu código, é uma dica de que ele é revertido por um bom motivo (talvez um dos motivos descritos acima). E ver um loop for forward tradicional pode indicar que a mudança pode ocorrer.
(Se a discussão sobre intenção não faz sentido para você, você e seu código podem se beneficiar assistindo a palestra de Crockford sobre Estilo de programação e seu cérebro .)
Agora é ainda melhor usar para ... de!
Há um debate sobre se é
for..of
ouforEach()
não preferível:Para obter o máximo suporte do navegador, é
for..of
necessário um polyfill para iteradores, tornando o aplicativo um pouco mais lento para executar e um pouco maior para baixar.Por esse motivo (e para incentivar o uso de
map
efilter
), alguns guias de estilo de front-end banemfor..of
completamente!Mas as preocupações acima não são aplicáveis aos aplicativos Node.js., onde
for..of
agora é bem suportado.E, além disso
await
, não funciona por dentroforEach()
. Usarfor..of
é o padrão mais claro nesse caso.Pessoalmente, costumo usar o que parecer mais fácil de ler, a menos que desempenho ou minificação se tornem uma grande preocupação. Portanto, hoje em dia eu prefiro usar em
for..of
vez deforEach()
, mas sempre usareimap
oufilter
oufind
ousome
quando aplicável. (Pelo bem de meus colegas, eu raramente usoreduce
.)Como funciona?
Você notará que essa
i--
é a cláusula do meio (onde geralmente vemos uma comparação) e a última cláusula está vazia (onde geralmente vemosi++
). Isso significa quei--
também é usado como condição para continuação. Fundamentalmente, é executado e verificado antes de cada iteração.Como pode começar
array.length
sem explodir?Como
i--
é executado antes de cada iteração, na primeira iteração, estaremos acessando o item noarray.length - 1
qual evita qualquer problema com os itens damatriz fora dos limitesundefined
.Por que ele não para de iterar antes do índice 0?
O loop interromperá a iteração quando a condição for
i--
avaliada como um valor de falsey (quando produzir 0).O truque é que
--i
, diferentemente , oi--
operador à direita diminui,i
mas gera o valor antes da diminuição. Seu console pode demonstrar isso:> var i = 5; [i, i--, i];
[5, 5, 4]
Portanto, na iteração final, eu era anteriormente 1 e a
i--
expressão o altera para 0, mas na verdade produz 1 ( verdade ) e, portanto, a condição passa. Na próxima iteraçãoi--
muda i a -1 , mas gera 0 (Falsey), fazendo com que a execução a cair imediatamente para fora da parte inferior do circuito.Nos tradicionais forward for loop,
i++
e++i
são intercambiáveis (como Douglas Crockford aponta). No entanto, no loop for reverso, porque nosso decréscimo também é nossa expressão de condição, devemos permanecer comi--
se queremos processar o item no índice 0.Curiosidades
Algumas pessoas gostam de desenhar uma flecha no
for
loop reverso e terminam com uma piscadela:Os créditos vão para a JMJ por me mostrar os benefícios e os horrores do inverso do loop.
fonte
Algumas linguagens de estilo C usam
foreach
para percorrer enumerações. Em JavaScript, isso é feito com afor..in
estrutura do loop :Há um problema.
for..in
percorrerá cada um dos membros enumeráveis do objeto e os membros em seu protótipo. Para evitar a leitura de valores herdados pelo protótipo do objeto, basta verificar se a propriedade pertence ao objeto:Além disso, o ECMAScript 5 adicionou um
forEach
método aoArray.prototype
qual pode ser usado para enumerar em uma matriz usando um calback (o polyfill está nos documentos para que você ainda possa usá-lo em navegadores mais antigos):É importante observar que
Array.prototype.forEach
não é interrompido quando o retorno de chamada retornafalse
. O jQuery e o Underscore.js fornecem suas próprias variaçõeseach
para fornecer loops que podem sofrer um curto-circuito.fonte
each
métodos que permitemreturn false
ser usados para romper o ciclo, mas comforEach
isso não é uma opção. Uma bandeira externo poderia ser usado (ieif (flag) return;
, mas só impediria o resto do corpo da função de execução,forEach
seria ainda continuam iteração sobre a coleção inteira.Se você deseja fazer um loop sobre uma matriz, use o
for
loop de três partes padrão .Você pode obter algumas otimizações de desempenho armazenando em cache
myArray.length
ou iterando-o para trás.fonte
length
. ;),
após uma tarefa não apresenta uma nova global, portanto, sua sugestão é ótima ! Eu estava confundindo isso com um problema diferente: o uso=
após uma atribuição cria uma nova global.var i, length, arrayItem;
antes do loop para evitar esse mal-entendido.Eu sei que este é um post antigo, e já existem muitas ótimas respostas. Para um pouco mais de completude, imaginei que jogaria outro usando o AngularJS . Obviamente, isso só se aplica se você estiver usando Angular, obviamente, no entanto, eu gostaria de colocar de qualquer maneira.
angular.forEach
leva 2 argumentos e um terceiro argumento opcional. O primeiro argumento é o objeto (matriz) a ser repetido, o segundo argumento é a função iteradora e o terceiro argumento opcional é o contexto do objeto (basicamente referido dentro do loop como 'this').Existem diferentes maneiras de usar o loop forEach de angular. O mais simples e provavelmente o mais usado é
Outra maneira útil para copiar itens de uma matriz para outra é
No entanto, você não precisa fazer isso, basta fazer o seguinte e é equivalente ao exemplo anterior:
Agora, existem prós e contras de usar a
angular.forEach
função em oposição aofor
loop com sabor de baunilha .Prós
angular.forEach
usará o loop ES5 forEach. Agora, chegarei à eficiência na seção contras, pois os loops forEach são muito mais lentos que os loops for. Menciono isso como profissional, porque é bom ser consistente e padronizado.Considere os 2 loops aninhados a seguir, que fazem exatamente a mesma coisa. Digamos que temos 2 matrizes de objetos e cada objeto contém uma matriz de resultados, cada um com uma propriedade Value que é uma string (ou qualquer outra coisa). Digamos que precisamos iterar sobre cada um dos resultados e, se forem iguais, execute alguma ação:
Concedido que este é um exemplo hipotético muito simples, mas escrevi triplamente incorporado para loops usando a segunda abordagem e foi muito difícil de ler e escrever para esse assunto.
Contras
angular.forEach
, e o nativoforEach
, aliás, são muito mais lentos que ofor
loop normal ... cerca de 90% mais lento . Portanto, para conjuntos de dados grandes, é melhor manter ofor
loop nativo .continue
é realmente suportado por " acidente ", para continuar com umaangular.forEach
simplesreturn;
instrução na função, oangular.forEach(array, function(item) { if (someConditionIsTrue) return; });
que fará com que ela continue fora da função para essa iteração. Isso também se deve ao fato de o nativoforEach
não suportar interrupção ou continuar.Tenho certeza de que existem vários outros prós e contras também, e fique à vontade para adicionar os que achar melhor. Eu acho que, se você precisar de eficiência, use apenas o
for
loop nativo para suas necessidades de loop. Mas, se os seus conjuntos de dados são menores e é conveniente desistir de alguma eficiência em troca da legibilidade e da capacidade de gravação, então, de todas as maneiras, jogue um poucoangular.forEach
naquele garoto mau.fonte
Se você não se importa de esvaziar a matriz:
x
conterá o último valor dey
e será removido da matriz. Você também pode usar oshift()
que fornecerá e removerá o primeiro itemy
.fonte
[1, 2, undefined, 3]
.[1, 2, 0, 3]
ou[true, true, false, true]
Uma implementação forEach ( veja em jsFiddle ):
fonte
Provavelmente o
for(i = 0; i < array.length; i++)
loop não é a melhor escolha. Por quê? Se você tem isso:O método chamará de
array[0]
paraarray[2]
. Primeiro, isso fará referência a variáveis que você nem sequer tem, depois não terá as variáveis na matriz e, terceiro, tornará o código em negrito. Olha aqui, é o que eu uso:E se você quiser que seja uma função, você pode fazer isso:
Se você quiser quebrar, um pouco mais de lógica:
Exemplo:
Retorna:
fonte
Existem três implementações
foreach
no jQuery da seguinte maneira.fonte
A partir do ECMAScript 6:
Onde
of
evita as esquisitices associadasin
e faz com que funcione como ofor
loop de qualquer outra linguagem, elet
vincula - sei
ao loop em oposição à função.As chaves (
{}
) podem ser omitidas quando há apenas um comando (por exemplo, no exemplo acima).fonte
Uma solução fácil agora seria usar a biblioteca underscore.js . Ele fornece muitas ferramentas úteis, como
each
e delegará automaticamente o trabalho para o nativoforEach
se disponível.Um exemplo de CodePen de como funciona é:
Veja também
Array.prototype.forEach()
.for each (variable in object)
está obsoleto como parte do padrão ECMA-357 ( EAX ).for (variable of object)
como parte da proposta Harmony (ECMAScript 6).fonte
Não há nenhum
for each
loop no JavaScript nativo . Você pode usar bibliotecas para obter essa funcionalidade (eu recomendo o Underscore.js ), use umfor
loop simples .No entanto, observe que pode haver razões para usar um
for
loop ainda mais simples (consulte a questão Estouro de pilha) Por que usar "for ... in" com uma iteração de matriz é uma péssima idéia? )fonte
Este é um iterador para lista NÃO esparsa, onde o índice começa em 0, que é o cenário típico ao lidar com document.getElementsByTagName ou document.querySelectorAll)
Exemplos de uso:
Exemplo 1
Exemplo 2
Cada tag p recebe
class="blue"
Exemplo 3
Qualquer outra tag p recebe
class="red"
>Exemplo 4
E, finalmente, as 20 primeiras tags p azuis são alteradas para verde
Cuidado ao usar string como função: a função é criada fora do contexto e deve ser usada apenas quando você tiver certeza do escopo da variável. Caso contrário, é melhor passar funções nas quais o escopo é mais intuitivo.
fonte
Existem algumas maneiras de percorrer uma matriz em JavaScript, como abaixo:
para - é o mais comum . Bloco de código completo para loop
while - executa um loop enquanto uma condição está concluída. Parece ser o loop mais rápido
do / while - também passa por um bloco de código enquanto a condição é verdadeira, será executada pelo menos uma vez
Laços funcionais -
forEach
,map
,filter
, tambémreduce
(eles percorrer a função, mas eles são usados se você precisa fazer alguma coisa com sua matriz, etc.Para obter mais informações e exemplos sobre programação funcional em matrizes, consulte a postagem do blog Programação funcional em JavaScript: mapear, filtrar e reduzir .
fonte
forEach
não é um loop "funcional", pois não retorna um novoArray
(na verdade, não retorna nada), apenas itera.ECMAScript 5 (a versão em JavaScript) para trabalhar com matrizes:
forEach - repete todos os itens da matriz e faz o que for necessário com cada item.
No caso, mais interessado na operação em array usando algum recurso embutido.
map - Cria uma nova matriz com o resultado da função de retorno de chamada. Esse método é bom para ser usado quando você precisar formatar os elementos da sua matriz.
reduzir - como o nome diz, reduz a matriz para um único valor, chamando a função fornecida que passa no elemento atual e o resultado da execução anterior.
every - Retorna true ou false se todos os elementos da matriz passam no teste na função de retorno de chamada.
filter - Muito semelhante a todos, exceto que o filtro retorna uma matriz com os elementos que retornam true para a função especificada.
fonte
Não há capacidade embutida para invadir
forEach
. Para interromper a execução, use oArray#some
seguinte abaixo:Isso funciona porque
some
retorna true assim que qualquer retorno de chamada, executado em ordem de matriz, retorna true, causando um curto-circuito na execução do restante. Resposta original, consulte Protótipo de matriz para algunsfonte
Eu também gostaria de adicionar isso como uma composição de um loop reverso e uma resposta acima para alguém que também gostaria dessa sintaxe.
Prós:
O benefício disso: você já tem a referência no primeiro, assim não precisará ser declarada posteriormente com outra linha. É útil ao fazer um loop pela matriz de objetos.
Contras:
Isso será interrompido sempre que a referência for falsa - falsey (indefinida, etc.). Pode ser usado como uma vantagem. No entanto, tornaria um pouco mais difícil de ler. E também, dependendo do navegador, pode "não" ser otimizado para funcionar mais rápido que o original.
fonte
jQuery maneira usando
$.map
:fonte
[undefined, 2, undefined, 4, undefined, 6, undefined]
.Usando loops com a desestruturação do ECMAScript 6 e o operador spread
A reestruturação e o uso do operador de propagação se mostraram bastante úteis para os iniciantes no ECMAScript 6 como sendo mais legíveis / estéticas, embora alguns veteranos em JavaScript possam considerá-lo confuso. Os juniores ou outras pessoas podem achar útil.
Exemplo 1:
for...of
Loop normal - não há truques aqui.Exemplo 2: Dividir palavras em caracteres
Exemplo 3: loop com um
key
evalue
Exemplo 4: Obter propriedades do objeto embutidas
Exemplo 5: obtenha propriedades profundas do objeto do que você precisa
Exemplo 6: O Exemplo 3 é usado com
.forEach
Exemplo 7: O Exemplo 4 é usado com
.forEach
Exemplo 8: O Exemplo 5 é usado com
.forEach
fonte
Uma maneira mais próxima da sua idéia seria usar o
Array.forEach()
que aceita uma função de fechamento que será executada para cada elemento da matriz.Outra maneira viável seria usar o
Array.map()
que funciona da mesma maneira, mas também pega todos os valores retornados e os retorna em uma nova matriz (essencialmente mapeando cada elemento para um novo), assim:fonte
map
não modifica os elementos da matriz, pois retorna uma nova matriz, com os itens dessa nova sendo o resultado da aplicação da função aos itens da matriz antiga.Você pode ligar paraEach assim:
forEach
iterará sobre a matriz que você fornecer e para cada iteração que possuir,element
que retém o valor dessa iteração. Se você precisar de um índice, poderá obter o índice atual passandoi
o segundo parâmetro na função de retorno de chamada para forEach.O Foreach é basicamente uma função de alta ordem, que assume outra função como parâmetro.
Resultado:
Você também pode iterar sobre uma matriz como esta:
fonte
Se você deseja percorrer uma matriz de objetos com a função de seta:
fonte
A sintaxe lambda geralmente não funciona no Internet Explorer 10 ou abaixo.
Eu costumo usar o
Se você é um fã de jQuery e já possui um arquivo jQuery em execução, deve reverter as posições dos parâmetros de índice e valor
fonte
Se você tem uma matriz enorme, deve usar
iterators
para obter alguma eficiência. Iteradores são uma propriedade de determinadas coleções de JavaScript (comoMap
,Set
,String
,Array
). Mesmo,for..of
usaiterator
sob o capô.Os iteradores melhoram a eficiência, permitindo que você consuma os itens de uma lista, um de cada vez, como se fossem um fluxo. O que torna um iterador especial é como ele percorre uma coleção. Outros loops precisam carregar toda a coleção antecipadamente para iterá-la, enquanto um iterador precisa conhecer apenas a posição atual na coleção.
Você acessa o item atual chamando o
next
método do iterador . O próximo método retornará ovalue
item atual e aboolean
para indicar quando você alcançou o final da coleção. A seguir, é apresentado um exemplo de criação de um iterador a partir de uma matriz.Transforme sua matriz regular em iterador usando um
values()
método como este:Você também pode transformar sua matriz regular em iterador usando o
Symbol.iterator
seguinte:Você também pode transformar seu regular
array
em umiterator
assim:NOTA :
iterable
por padrão. Usefor..in
nesse caso, porque, em vez de valores, ele funciona com chaves.Você pode ler mais sobre
iteration protocol
aqui .fonte
Se você quiser usar
forEach()
, será parecido com -Se você quiser usar
for()
, será parecido com -fonte
De acordo com o novo recurso atualizado ECMAScript 6 (ES6) e ECMAScript 2015, você pode usar as seguintes opções com loops:
fonte
atuação
Hoje (2019-12-18) realizo testes no meu macOS v10.13.6 (High Sierra), no Chrome v 79.0, Safari v13.0.4 e Firefox v71.0 (64 bits) - conclusões sobre otimização (e micro-otimização que geralmente não vale a pena introduzi-lo no código porque o benefício é pequeno, mas a complexidade do código aumenta).
Parece que o tradicional
for i
( Aa ) é uma boa opção para escrever código rápido em todos os navegadores.As outras soluções, como
for-of
( Ad ), todas no grupo C. ... geralmente são de 2 a 10 (e mais) vezes mais lentas que Aa , mas para pequenas matrizes é aceitável usá-la - por uma questão de maior clareza do código.Os loops com comprimento de array armazenados em cache em
n
( Ab, Bb, Be ) são algumas vezes mais rápidos, outras não. Provavelmente, os compiladores detectam automaticamente essa situação e introduzem o cache. As diferenças de velocidade entre as versões em cache e sem cache ( Aa, Ba, Bd ) são de aproximadamente 1%, portanto, parece que a introduçãon
é uma micro otimização .As
i--
soluções semelhantes em que o loop inicia a partir do último elemento da matriz ( Ac, Bc ) geralmente são aproximadamente 30% mais lentas que as soluções avançadas - provavelmente o motivo é o modo como o cache de memória da CPU está funcionando - a leitura direta da memória é mais ideal para o cache da CPU). É recomendável NÃO UTILIZAR essas soluções.Detalhes
Nos testes, calculamos a soma dos elementos da matriz. Realizo um teste para matrizes pequenas (10 elementos) e matrizes grandes (elementos 1M) e as divido em três grupos:
for
testeswhile
testesMostrar snippet de código
Resultados entre navegadores
Resultados para todos os navegadores testados
navegadores **
Matriz com 10 elementos
Resultados para o Chrome. Você pode executar o teste em sua máquina aqui .
Matriz com 1.000.000 de elementos
Resultados para o Chrome. Você pode realizar o teste em sua máquina aqui
fonte
Resumo:
Ao iterar sobre uma matriz, geralmente queremos atingir um dos seguintes objetivos:
Queremos iterar sobre a matriz e criar uma nova matriz:
Array.prototype.map
Queremos iterar sobre a matriz e não criar uma nova matriz:
Array.prototype.forEach
for..of
cicloEm JavaScript, existem muitas maneiras de atingir esses dois objetivos. No entanto, alguns são mais convenientes que outros. Abaixo, você encontra alguns métodos mais usados (o IMO mais conveniente) para realizar a iteração de matriz em JavaScript.
Criando nova matriz:
Map
map()
é uma função localizada naArray.prototype
qual pode transformar todos os elementos de uma matriz e, em seguida, retorna uma nova matriz.map()
toma como argumento uma função de retorno de chamada e funciona da seguinte maneira:O retorno de chamada para o qual passamos
map()
como argumento é executado para cada elemento. Em seguida, é retornada uma matriz com o mesmo comprimento da matriz original. Nesse novo elemento da matriz, é transformada pela função de retorno de chamada passada como argumento paramap()
.A diferença distinta entre
map
e outro mecanismo de loop comoforEach
e umfor..of
loop é quemap
retorna uma nova matriz e deixa intacta a matriz antiga (exceto se você a manipular explicitamente com pensamentos comosplice
).Além disso, observe que o
map
retorno de chamada da função fornece o número do índice da iteração atual como um segundo argumento. Além disso, o terceiro argumento fornece a matriz na qualmap
foi chamada? Às vezes, essas propriedades podem ser muito úteis.Loop usando
forEach
forEach
é uma função localizada naArray.prototype
qual assume uma função de retorno de chamada como argumento. Em seguida, ele executa essa função de retorno de chamada para todos os elementos da matriz. Ao contrário damap()
função, a função forEach não retorna nada (undefined
). Por exemplo:Assim como a
map
função, oforEach
retorno de chamada fornece o número do índice da iteração atual como um segundo argumento. Além disso, o terceiro argumento fornece a matriz na qualforEach
foi chamada?Repita os elementos usando
for..of
O
for..of
loop percorre todos os elementos de uma matriz (ou qualquer outro objeto iterável). Funciona da seguinte maneira:No exemplo acima,
element
representa um elemento do array earr
é o array que queremos fazer um loop. Observe que o nomeelement
é arbitrário, e poderíamos ter escolhido outro nome como 'el' ou algo mais declarativo quando isso for aplicável.Não confunda o
for..in
loop com ofor..of
loop.for..in
percorrerá todas as propriedades enumeráveis da matriz, enquanto ofor..of
loop percorrerá apenas os elementos da matriz. Por exemplo:fonte