Para cada matriz em javascript?

Como posso ver todas as entradas em uma matriz usando javascript?

Eu pensei que era algo assim:

 forEach(instance in theArray) 

Onde theArray é minha matriz, mas parece errado.

4041
17 февр. Dante1986 set em 17 de fevereiro 2012-02-17 16:51 '12 em 4:51 PM 2012-02-17 16:51
@ 32 respostas
  • 1
  • 2

Tl; DR

  • Não use for-in se você não usá-lo com proteção ou, pelo menos, não sabe por que ele pode morder você.
  • Suas melhores apostas são geralmente

    • for-of loop (apenas para ES2015 +),
    • Array#forEach ( spec | MDN ) (ou seus parentes some e semelhantes) (somente ES5 +)
    • simples antiquado for loops,
    • ou entrada for-in com proteção.

Mas ainda há muito para explorar, continue a ler ...


O JavaScript possui uma poderosa semântica para transformar ciclicamente arrays e objetos do tipo array. Eu dividi a resposta em duas partes: opções para arrays autênticos e opções para coisas que são semelhantes apenas a arrays, como o objeto arguments , outros objetos iteráveis ​​(ES2015 +), coleções de DOM, etc.

Eu rapidamente percebo que agora você pode usar as opções do ES2015, mesmo em motores ES5, enviando o ES2015 para o ES5. Encontre "ES2015 transpiling" / "ES6 transpiling" para mais ...

Bem, veja 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. Use forEach e relacionado (ES5 +)
  2. Use loop simples
  3. Use corretamente for-in
  4. Use for-of (use iterador implícito) (ES2015 +)
  5. Use o iterador explicitamente (ES2015 +)

Detalhes:

1. Use forEach e relacionado

Em qualquer ambiente indefinidamente moderno (bem, não no IE8), onde você tem acesso às funções Array adicionadas pelo ES5 (diretamente ou usando preenchimentos do polyple), você pode usar forEach ( spec | MDN ):

 var a = ["a", "b", "c"]; a.forEach(function(entry) { console.log(entry); }); 

forEach aceita uma função de retorno de chamada e, opcionalmente, um valor usado assim ao chamar esse retorno de chamada (não usado acima). O retorno de chamada é chamado para cada entrada na matriz para ignorar 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 registro, o índice desse registro e o link para o array que você está repetindo (caso sua função ainda não o tenha).

Se você não oferece suporte a navegadores legados, como o IE8 (que a NetApps mostra em mais de 4% do mercado no momento da redação deste artigo em setembro de 2016), você pode usar alegremente o forEach em uma página da web universal sem um layout de página. Se você precisar oferecer suporte a navegadores desatualizados, será fácil executar a operação de forEach / polyfilling forEach (encontre "es5 shim" para várias opções).

forEach tem a vantagem de não ser necessário declarar valores de indexação e variáveis ​​na área de conteúdo, pois eles são fornecidos como argumentos para a função de iteração e são tão bem orientados para essa iteração.

Se você está preocupado com o tempo que leva para executar uma chamada de função para cada registro de matriz, não seja; detalhes

Além disso, forEach é uma função "loop through them all", mas o ES5 definiu várias outras "elaborações úteis por meio de funções e coisas do array", incluindo:

  • every (pára o loop na primeira vez em que o callback retorna false ou algo falso)
  • some (pára o loop na primeira vez que o callback retorna true ou algo plausível)
  • filter (cria uma nova matriz que inclui elementos nos quais a função de filtro retorna true e omite aqueles onde ela retorna false )
  • map (cria uma nova matriz de valores de retorno de retorno)
  • reduce (incrementar um valor, re-invocar um retorno de chamada, passar valores anteriores, ver a especificação para detalhes, útil para somar o conteúdo de um array e muitas outras coisas)
  • reduceRight (por exemplo, reduce , mas funciona em ordem decrescente, não em ordem crescente)

2. Use um loop for simples

Às vezes as formas antigas são 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 mudar durante o ciclo e seu desempenho for um código sensível (improvável), uma versão um pouco mais complicada da captura com o tamanho da frente pode ser um pouco mais rápida:

 var index, len; var a = ["a", "b", "c"]; for (index = 0, len = a.length; index < len; ++index) { console.log(a[index]); } 

E / ou contando de volta:

 var index; var a = ["a", "b", "c"]; for (index = a.length - 1; index >= 0; --index) { console.log(a[index]); } 

Mas com os modernos mecanismos de JavaScript, você raramente precisa descobrir esse último suco.

No ES2015 e superior, você pode tornar suas variáveis ​​de índice e valor locais for loops for :

 let a = ["a", "b", "c"]; for (let index = 0; index < a.length; ++index) { let value = a[index]; } //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 apenas o value mas também o index recriados para cada iteração do loop, ou seja, os closures criados na tag de loop contêm uma referência ao index (e value ) criado para esta iteração específica:

 let divs = document.querySelectorAll("div"); for (let index = 0; index < divs.length; ++index) { divs[index].addEventListener('click', e => { alert("Index is: " + index); }); } 

Se você tivesse cinco divs, você obteria "Index is: 0", se você clicasse no primeiro e "Index fosse: 4", se você clicasse no último. Isso não funciona se você usar var invés de let .

3. Use for-in corretamente.

Você vai levar as pessoas dizendo para você usar for-in , mas isso não é o que for-in para . for-in escrito através das propriedades enumeradas do objeto, e não dos índices da matriz. Pedido não garantido , mesmo no ES2015 (ES6). O ES2015 determina a ordem das propriedades de um objeto (usando [[OwnPropertyKeys]] , [[Enumerate]] e itens que as utilizam como Object.getOwnPropertyKeys ), mas não especifica que o for-in seguirá essa ordem. (Detalhes nesta outra resposta .)

No entanto, isso pode ser útil, especialmente para matrizes esparsas , se você usar as precauções 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 are explained /^0$|^[1-9]\d*$/.test(key)  // and then hidden key <= 4294967294 // away below ) { console.log(a[key]); } } 

Observe as duas verificações:

  1. Que o objeto tem sua própria propriedade sob este nome (e não aquele que ele herda de seu protótipo), e

  2. Que a chave é uma string numérica de base 10 em sua forma usual de string, e seu valor é <= 2 ^ 32 - 2 (que é 4.294.967.294). De onde vem esse número? Isso faz parte da definição do índice da matriz na especificação . Outros números (números não inteiros, números negativos, números maiores que 2 ^ 32 - 2) não são índices de matriz. A causa de 2 ^ 32 - 2 é o que torna o maior valor de índice menor que 2 ^ 32 - 1 , que é o valor máximo do length array. (Por exemplo, o comprimento da matriz corresponde a um inteiro não assinado de 32 bits.) (Uma confirmação da RobG para indicar em um comentário ao meu post que meu teste anterior não estava correto).

Este é um pequeno bit de sobrecarga adicional para cada iteração de loops na maioria dos arrays, mas se você tiver um array esparso, isso pode ser uma maneira mais eficiente de fazer loop, porque esses são apenas loops para registros que realmente existem. Por exemplo, para o array acima, fazemos um loop três vezes (para as teclas "0" , "10" e "10000" - lembre-se, estas são linhas), e não 10,001 vezes.

Agora você não quer escrevê-lo toda vez, então pode colocá-lo em seu kit de ferramentas:

 function arrayHasOwnIndex(array, prop) { return array.hasOwnProperty(prop)  /^0$|^[1-9]\d*$/.test(prop)  prop <= 4294967294; // 2^32 - 2 } 

E então vamos usá-lo assim:

 for (key in a) { if (arrayHasOwnIndex(a, key)) { console.log(a[key]); } } 

Ou, se você está interessado apenas no teste “bom o suficiente para a maioria dos casos”, você pode usá-lo, mas enquanto estiver próximo, isso não está correto:

 for (key in a) { // "Good enough" for most cases if (String(parseInt(key, 10)) === key  a.hasOwnProperty(key)) { console.log(a[key]); } } 

4. Use for-of (use iterador implícito) (ES2015 +)

O ES2015 adiciona iteradores ao JavaScript. A maneira mais fácil de usar os iteradores é o novo operador for-of . Parece assim:

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

Conclusão:

 um b c

Nos bastidores, que obtém um iterador do array e passa por ele, obtém valores dele. Não há problema com o uso for-in , porque ele usa um iterador definido por um objeto (matriz) e as matrizes determinam que seus iteradores repetem seus registros (e não suas propriedades). Diferentemente do for-in no ES5, a ordem em que os registros são visualizados é a ordem numérica de seus índices.

5. Use o iterador explicitamente (ES2015 +)

Às vezes você pode usar explicitamente um iterador. Você pode fazer isso também, embora seja muito mais complicado do que for-of futuro. Parece assim:

 var a = ["a", "b", "c"]; var it = a.values(); var entry; while (!(entry = it.next()).done) { console.log(entry.value); } 

Um 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 tem uma propriedade, done , informa se foi feito e o value propriedade com o valor dessa iteração. ( done opcional se for false , o value é opcional se não for undefined ).

O value varia dependendo do iterador; arrays suportam (pelo menos) três funções que retornam iteradores:

  • values() : Este é o que eu usei acima. Ele retorna um iterador, onde cada value é um registro de matriz para essa iteração ( "a" , "b" e "c" no exemplo acima).
  • keys() : Retorna um iterador, onde cada value é a chave para esta iteração (então, para o nosso acima, haverá a "0" e, em seguida, "1" e, em seguida, "2" ).
  • entries() : retorna um iterador, onde cada value é um array na forma de [key, value] para esta iteração.

Para objetos como uma matriz

Além dos arrays verdadeiros, há também objetos do tipo array que possuem a propriedade length e propriedades com nomes numéricos: instâncias de NodeList , um objeto de arguments , etc. Como podemos NodeList seu conteúdo?

Use qualquer um dos parâmetros acima para matrizes.

Pelo menos algumas, e talvez a maioria ou até mesmo todas as matrizes acima são freqüentemente usadas igualmente bem para objetos do tipo array:

  1. Use forEach e relacionado (ES5 +)

    As várias funções no Array.prototype são "intencionalmente genéricas" e geralmente podem ser usadas para objetos como uma matriz através da Function#call Function#apply ou Function#apply . (Consulte o aviso de isenção de responsabilidade para objetos fornecidos pelo host ao final dessa resposta, mas esse é um problema raro).

    Suponha que você queira usar forEach em childNodes Node childNodes . Você faria isso:

     Array.prototype.forEach.call(node.childNodes, function(child) { // Do something with 'child' }); 

    Se você for fazer muito isso, você pode querer obter uma cópia da referência de função em uma variável para ser reutilizada, 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 loop simples

    Obviamente, um loop for simples é aplicado a objetos como um array.

  3. Use corretamente for-in

    for-in com as mesmas garantias que com um array, deve funcionar com objetos semelhantes a um array; Reservas podem ser necessárias para itens fornecidos pelo host para o número 1 acima.

  4. Use for-of (use iterador implícito) (ES2015 +)

    for-of usará o iterador fornecido pelo objeto (se houver); teremos que ver como isso acontece com vários objetos semelhantes a array, especialmente com arquivos host. Por exemplo, a especificação para o NodeList de querySelectorAll foi atualizada para suportar a iteração. A especificação para o HTMLCollection de getElementsByTagName não getElementsByTagName .

  5. Use o iterador explicitamente (ES2015 +)

    Veja o número 4, precisamos ver como os iteradores se desdobram.

Crie um array verdadeiro

Em outros casos, você pode converter um objeto como uma matriz em uma matriz verdadeira. Para fazer isso é surpreendentemente fácil:

  1. Use o método de matriz de slice

    Podemos usar o método de matriz de slice , que, como os outros métodos mencionados acima, é "intencionalmente genérico" e, portanto, pode ser usado com objetos do tipo array, por exemplo:

     var trueArray = Array.prototype.slice.call(arrayLikeObject); 

    Então, por exemplo, se quisermos converter um NodeList em um array real, poderíamos fazer isso:

     var divs = Array.prototype.slice.call(document.querySelectorAll("div")); 

    Consulte "Cuidado para objetos fornecidos pelo host" abaixo. Em particular, observe que isso não funcionará no IE8 e anterior, o que não permite o uso de objetos fornecidos pelo host this .

  2. Use a sintaxe de distribuição ( ... )

    Também é possível usar a sintaxe de distribuição do ES2015 com mecanismos JavaScript que suportam esse recurso:

     var trueArray = [...iterableObject]; 

    Então, por exemplo, se quisermos converter um NodeList em um array verdadeiro, com a sintaxe de propagação, ele se torna bastante breve:

     var divs = [...document.querySelectorAll("div")]; 
  3. Use Array.from (especificação) | (MDN)

    Array.from (ES2015 +, mas facilmente preenchido com poly) cria uma matriz a partir de um objeto como uma matriz, se necessário, passando primeiro os registros pela função correspondente. Então:

     var divs = Array.from(document.querySelectorAll("div")); 

    Ou, se você deseja obter uma matriz de nomes de tags para elementos com uma determinada classe, deve usar 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; }); 

Atenção para as instalações fornecidas pelo host

Se você usar Array.prototype funções Array.prototype com objetos como hosts (listas DOM e outras fornecidas pelo navegador, em vez do mecanismo JavaScript), é necessário testar os ambientes de destino para garantir que o objeto host fornecido se comporta está correto. A maioria deles se comporta corretamente (agora), mas é importante verificar. A razão é que a maioria dos métodos do Array.prototype que você provavelmente quer usar depende do objeto fornecido pelo host, dando uma resposta honesta ao resumo [[HasProperty]] . No momento da redação deste artigo, os navegadores fizeram um trabalho muito bom, mas a especificação 5.1 sugeriu que o objeto fornecido pelo host talvez não seja justo. Isso está no §8.6.2 , alguns parágrafos abaixo da grande tabela no início desta seção, onde diz:

Objetos de host podem implementar esses métodos internos de qualquer maneira, salvo indicação em contrário; por exemplo, uma possibilidade é que [[Get]] e [[Put]] para um objeto de host específico realmente recuperam e salvam valores de propriedade, mas [[HasProperty]] sempre gera false .

(Não consegui encontrar um texto equivalente na especificação ES2015, mas ainda tem que ser.) Novamente, como escrever um host comum do tipo de objeto fornecido em navegadores modernos [instâncias NodeList , por exemplo], faça o [[HasProperty]] correto, mas importante verifique.)

6292
17 февр. A resposta é dada por TJ Crowder 17 de fevereiro 2012-02-17 16:53 '12 em 4:53 pm 2012-02-17 16:53

Edit : esta resposta está irremediavelmente desatualizada. Para uma abordagem mais moderna, observe os métodos disponíveis na matriz . Os métodos de interesse podem ser:

  • para cada
  • cartão
  • o filtro
  • fecho de correr
  • reduzir
  • cada
  • um pouquinho

A maneira padrão de iterar um array em JavaScript é for -loop vanilla:

border=0
 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 é boa apenas se você tiver uma matriz densa e cada índice estiver ocupado por um elemento. Se a matriz é escassa, então com essa abordagem você pode ter problemas de desempenho, já que você passará por muitos índices que realmente não existem na matriz. Nesse caso, é melhor usar for.. in -loop. No entanto, você deve usar as precauções apropriadas para garantir que apenas as propriedades necessárias da matriz (ou seja, elementos da matriz) estejam em for..in , porque for..in -loop também será listado em navegadores legados ou se as propriedades adicionais forem definidas como enumerable .

No ECMAScript 5 , o método forEach será usado para o protótipo do array, mas não é suportado em navegadores herdados. Portanto, para poder usá-lo consistentemente, você deve ter um ambiente que ofereça suporte a ele (por exemplo, Node.js para JavaScript do lado do servidor) ou use o "Polyfill". O Polyfill para essa funcionalidade, no entanto, é trivial e, como facilita a leitura do código, ele deve ser incluído no Polyfill.

470
17 февр. Resposta dada por PatrikAkerstrand em 17 fev 2012-02-17 16:55 '12 em 4:55 pm 2012-02-17 16:55

Se você estiver usando a biblioteca jQuery , você pode usar jQuery.each :

 var length = yourArray.length; for (var i = 0; i < length; i++) { // Do something with yourArray[i]. } 
214
17 февр. A resposta é dada Poonam 17 de fevereiro 2012-02-17 17:01 '12 às 17:01 2012-02-17 17:01

Loop de volta

Eu acho que o contrário do ciclo merece uma menção aqui:

 for (var i = array.length; i--; ) { // process array[i] } 

Benefícios:

  • Você não precisa declarar uma variável temporária len ou compará-la com array.length em cada iteração, o que pode ser otimização de minuto.
  • Removendo irmãos do DOM na ordem inversa é geralmente mais eficiente . (O navegador precisa mover menos elementos nas matrizes internas.)
  • Se você alterar uma matriz durante um loop, em ou após um índice I (por exemplo, excluir ou inserir um elemento na array[i] ), um loop direto ignorará um elemento deslocado para a esquerda para posicionar i ou verificar novamente o i-ésimo elemento que foi deslocado para a direita. No loop tradicional, você pode atualizar i para apontar para o próximo elemento que precisa ser processado - 1, mas simplesmente mudar a direção da iteração é geralmente uma solução mais simples e elegante .
  • Da mesma forma, ao alterar ou excluir elementos DOM aninhados , o processamento reverso pode ignorar erros . Por exemplo, considere alterar o innerHTML do nó pai antes de processar seus filhos. No momento em que o nó filho for atingido, ele será separado do DOM, substituindo-o por um novo descendente quando o pai innerHTML for gravado.
  • mais curto e lido do que algumas outras opções disponíveis. Embora perde para forEach() e para ES6 for ... of .

Desvantagens:

  • Ele processa os itens na ordem inversa. Se você construiu uma nova matriz a partir dos resultados ou impressa na tela, a saída será obviamente cancelada em relação à ordem original.
  • Неоднократно вставляя братьев и сестер в DOM в качестве первого ребенка, чтобы сохранить их порядок, менее эффективен . (В браузере все равно придется перекладывать вещи.) Чтобы создавать узлы DOM эффективно и упорядоченно, просто переходите вперед и добавьте как обычно (а также используйте "фрагмент документа" ).
  • Обратный цикл запутывает для младших разработчиков. (Вы можете считать это преимущество, в зависимости от вашего прогноза.)

Должен ли я всегда использовать его?