Para cada um sobre uma matriz em JavaScript


4684

Como posso percorrer todas as entradas de uma matriz usando JavaScript?

Eu pensei que era algo assim:

forEach(instance in theArray)

Onde theArrayestá minha matriz, mas isso parece estar incorreto.


16
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.
Slaven Rezic

36
Array.ForEach é cerca de 95% mais lento que para () para cada um para matrizes em JavaScript. Veja este teste de desempenho on-line: jsperf.com/fast-array-foreach via coderwall.com/p/kvzbpa
molokoloco

77
Para muitas situações em que 95% mais devagar não será significativo, blog.niftysnippets.org/2012/02/foreach-and-runtime-cost.html #
David Sykes

7
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ê.
  • Suas melhores apostas são geralmente

    • um for-ofloop (apenas ES2015 +),
    • Array#forEach( spec| MDN) (ou seus parentes somee similares) (somente ES5 +),
    • um simples forlaço antiquado ,
    • ou for-incom 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 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"):

  1. Uso forEache afins (ES5 +)
  2. Use um forloop simples
  3. Use for-in corretamente
  4. Use for-of(use um iterador implicitamente) (ES2015 +)
  5. 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]);
}

E / ou contando para trás:

var index;
var a = ["a", "b", "c"];
for (index = a.length - 1; index >= 0; --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"

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

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-in corretamente

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:

  • É uma matriz esparsa com lacunas enormes , ou
  • 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 array
var 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]);
    }
}

Observe as três verificações:

  1. Que o objeto tem sua própria propriedade com esse nome (não herdado de seu protótipo) e

  2. Que a chave tem todos os dígitos decimais (por exemplo, forma normal de string, não notação científica) e

  3. 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:

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-ofdeclaração. Se parece com isso:

const a = ["a", "b", "c"];
for (const val of a) {
    console.log(val);
}

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:

  1. 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`
    });
  2. Use um forloop simples

    Obviamente, um forloop simples se aplica a objetos do tipo array.

  3. Use for-in corretamente

    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.

  4. 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.

  5. 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:

  1. 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.

  2. 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")];
  3. 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.)


44
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.


2
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].
}

2
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..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 mape filter), alguns guias de estilo de front-end banem for..ofcompletamente!

  • Mas as preocupações acima não são aplicáveis ​​aos aplicativos Node.js., onde for..ofagora é bem suportado.

  • E, além disso await , não funciona por dentro forEach(). Usar for..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..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++) { ... }   // Forwards

for (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 limites undefined .

  • 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.


3
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).
Joeytwiddle

84

Algumas linguagens de estilo C usam foreachpara percorrer enumerações. Em JavaScript, isso é feito com a for..inestrutura do loop :

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):

arr.forEach(function (val, index, theArray) {
    //do stuff
});

É 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.


3
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.


6
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:

angular.forEach(temp, function(item) {
    temp2.push(item);
});

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 loop
for (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.


34

Se você não se importa de esvaziar a matriz:

var x;

while(x = y.pop()){ 

    alert(x); //do something 

}

xconterá o último valor de ye será removido da matriz. Você também pode usar o shift()que fornecerá e removerá o primeiro item y.


4
Não funciona se você tiver uma matriz esparsa [1, 2, undefined, 3].
M. Grzywaczewski

2
... ou realmente qualquer coisa falsey: [1, 2, 0, 3]ou[true, true, false, true]
joeytwiddle

31

Uma implementação forEach ( veja em jsFiddle ):

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

2
iterador nisso, está fazendo um cálculo desnecessário de comprimento. Em um caso ideal, o comprimento da lista deve ser calculado apenas uma vez.
Midhun Krishna

2
@MIdhunKrishna Atualizei minha resposta e o jsFiddle, mas saiba que não é tão simples quanto você pensa. Verifique esta questão
nmoliveira

2
A implementação completa e correta pode ser encontrada aqui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
marciowb 6/16

29

Provavelmente o for(i = 0; i < array.length; i++)loop não é a melhor escolha. Por quê? Se você tem isso:

var array = new Array();
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;
        }
    }
}

Exemplo:

foreach(array, function(el){
    if(el != "!"){
        console.log(el);
    } else {
        console.log(el+"!!");
    }
});

Retorna:

//Hello
//World
//!!!

29

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

2
O log do console é apenas para a demonstração. Isso é um exemplo de execução completa.
Rajesh Paul

29

A partir do ECMAScript 6:

list = [0, 1, 2, 3]
for (let obj of list) {
    console.log(obj)
}

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).


28

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.

Um exemplo de CodePen de como funciona é:

var arr = ["elemA", "elemB", "elemC"];
_.each(arr, function(elem, index, ar)
{
...
});

Veja também


23

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 .

for (var instance in objects) {
   ...
}

No entanto, observe que pode haver razões para usar um forloop 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? )

var instance;
for (var i=0; i < objects.length; i++) {
    var instance = objects[i];
    ...
}

22

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

    return this;
}

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]

Exemplo 2

each.call(document.getElementsByTagName('p'), "this.className = data;",'blue');

Cada tag p recebe class="blue"

Exemplo 3

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.


21

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;
<p id="example"></p>

while - executa um loop enquanto uma condição está concluída. Parece ser o loop mais rápido

var text = "";
var i = 0;
while (i < 10) {
    text +=  i + ") something<br>";
    i++;
}
document.getElementById("example").innerHTML = text;
<p id="example"></p>

do / while - também passa por um bloco de código enquanto a condição é verdadeira, será executada pelo menos uma vez

var text = ""
var i = 0;

do {
    text += i + ") something <br>";
    i++;
}
while (i < 10);

document.getElementById("example").innerHTML = text;
<p id="example"></p>

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 function
var numbers = [65, 44, 12, 4];
document.getElementById("example").innerHTML = numbers.map(function(num){return num * 2});
<p id="example"></p>

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 .


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.

[1,2,3,4].reduce(function(previous, current) {
  return previous + current;
});
// Output: 10
// 1st iteration: previous=1, current=2 => result=3
// 2nd iteration: previous=3, current=3 => result=6
// 3rd iteration: previous=6, current=4 => result=10

every - Retorna true ou false se todos os elementos da matriz passam no teste na função de retorno de chamada.

// Check if everybody has 18 years old of more.
var ages = [30, 43, 18, 5];
ages.every(function(elem) {
  return elem >= 18;
});

// Output: false

filter - Muito semelhante a todos, exceto que o filtro retorna uma matriz com os elementos que retornam true para a função especificada.

// Finding the even numbers
[1,2,3,4,5,6].filter(function(elem){
  return (elem % 2 == 0)
});

// Output: [2,4,6]

16

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


13

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.


12

jQuery maneira usando $.map:

var data = [1, 2, 3, 4, 5, 6, 7];

var newData = $.map(data, function(element) {
    if (element % 2 == 0) {
        return element;
    }
});

// newData = [2, 4, 6];

1
Eu acho que a saída é mais provável [undefined, 2, undefined, 4, undefined, 6, undefined].

10

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.

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

Exemplo 2: Dividir palavras em caracteres

let arrFruits = ['apple', 'orange', 'banana'];

for (let [firstLetter, ...restOfTheWord] of arrFruits) {
  // Create a shallow copy using the spread operator
  let [lastLetter] = [...restOfTheWord].reverse();
  console.log(firstLetter, lastLetter, restOfTheWord);
}

Exemplo 3: loop com um keyevalue

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

Exemplo 4: Obter propriedades do objeto embutidas

let arrWithObjects = [{
    name: 'Jon',
    age: 32
  },
  {
    name: 'Elise',
    age: 33
  }
];

for (let { name, age: aliasForAge } of arrWithObjects) {
  console.log(name, aliasForAge);
}

Exemplo 5: obtenha propriedades profundas do objeto do que você precisa

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

for (let { name, tags: [firstItemFromTags, ...restOfTags] } of arrWithObjectsWithArr) {
  console.log(name, firstItemFromTags, restOfTags);
}

Exemplo 6: O Exemplo 3 é usado com.forEach

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

Exemplo 7: O Exemplo 4 é usado com.forEach

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

Exemplo 8: O Exemplo 5 é usado com.forEach

let arrWithObjectsWithArr = [{
    name: 'Jon',
    age: 32,
    tags: ['driver', 'chef', 'jogger']
  },
  {
    name: 'Elise',
    age: 33,
    tags: ['best chef', 'singer', 'dancer']
  }
];

arrWithObjectsWithArr.forEach(({
  name,
  tags: [firstItemFromTags, ...restOfTags]
}) => {
  console.log(name, firstItemFromTags, restOfTags);
});


7

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:

var myArray = [1, 2, 3];
myArray = myArray.map(
  (item) => {
    return item + 1;
  }
);

console.log(myArray); // [2, 3, 4]

1
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:

1
3
2

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
}

6

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');
})


6

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

5

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

Você também pode transformar sua matriz regular em iterador usando o Symbol.iteratorseguinte:

const myArr = [2,3,4]

let it = myArr[Symbol.iterator]();

console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

Você também pode transformar seu regular arrayem um iteratorassim:

let myArr = [8, 10, 12];

function makeIterator(array) {
    var nextIndex = 0;
    
    return {
       next: function() {
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
};

var it = makeIterator(myArr);

console.log(it.next().value);   // {value: 8, done: false}
console.log(it.next().value);   // {value: 10, done: false}
console.log(it.next().value);   // {value: 12, done: false}
console.log(it.next().value);   // {value: undefined, done: true}

NOTA :

  • Os iteradores são de natureza esgotável.
  • Objetos não são iterablepor padrão. Use for..innesse caso, porque, em vez de valores, ele funciona com chaves.

Você pode ler mais sobre iteration protocol aqui .


5

Se você quiser usar forEach(), será parecido com -

theArray.forEach ( element => {
    console.log(element);
});

Se você quiser usar for(), será parecido com -

for(let idx = 0; idx < theArray.length; idx++){
    let element = theArray[idx];
    console.log(element);
}

4

De acordo com o novo recurso atualizado ECMAScript 6 (ES6) e ECMAScript 2015, você pode usar as seguintes opções com loops:

para loops

for(var i = 0; i < 5; i++){
  console.log(i);
}

// Output: 0,1,2,3,4

para ... em loops

let obj = {"a":1, "b":2}

for(let k in obj){
  console.log(k)
}

// Output: a,b

Array.forEach ()

let array = [1,2,3,4]

array.forEach((x) => {
  console.log(x);
})

// Output: 1,2,3,4

para ... de loops

let array = [1,2,3,4]

for(let x of array){
  console.log(x);
}

// Output: 1,2,3,4

enquanto loops

let x = 0

while(x < 5){
  console.log(x)
  x++
}

// Output: 1,2,3,4

fazer ... enquanto loops

let x = 0

do{
  console.log(x)
  x++
}while(x < 5)

// Output: 1,2,3,4

4

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çã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:

  • A - fortestes
  • B - whiletestes
  • C - outros métodos alternativos

Resultados entre navegadores

Resultados para todos os navegadores testados

Digite a descrição da imagem aquinavegadores **

Matriz com 10 elementos

Resultados para o Chrome. Você pode executar o teste em sua máquina aqui .

Digite a descrição da imagem aqui

Matriz com 1.000.000 de elementos

Resultados para o Chrome. Você pode realizar o teste em sua máquina aqui

Digite a descrição da imagem aqui


4

Resumo:

Ao iterar sobre uma matriz, geralmente queremos atingir um dos seguintes objetivos:

  1. Queremos iterar sobre a matriz e criar uma nova matriz:

    Array.prototype.map

  2. Queremos iterar sobre a matriz e não criar uma nova matriz:

    Array.prototype.forEach

    for..of ciclo

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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.