Guia JavaScript Parte 5: matrizes e loops

Hoje, na quinta parte da tradução do curso JavaScript, falaremos sobre matrizes e loops. Matrizes são usadas para resolver muitos problemas. Geralmente, trabalhe com matrizes usando loops.

Parte 1: primeiro programa, recursos de linguagem, padrões
Parte 2: estilo do código e estrutura do programa
Parte 3: variáveis, tipos de dados, expressões, objetos
Parte 4: recursos
Parte 5: matrizes e loops
Parte 6: exceções, ponto e vírgula, literais curinga
Parte 7: modo estrito, esta palavra-chave, eventos, módulos, cálculos matemáticos
Parte 8: Visão geral dos recursos do ES6
Parte 9: Visão geral dos padrões ES7, ES8 e ES9



Matrizes


Matrizes, objetos do tipo Array , evoluem junto com outros mecanismos da linguagem. São listas de valores numerados.

O primeiro elemento da matriz possui um índice (chave) de 0; essa abordagem é usada em muitas linguagens de programação.

Nesta seção, consideraremos métodos modernos de trabalho com matrizes.

▍Inicializando matrizes


Aqui estão algumas maneiras de inicializar matrizes.

 const a = [] const a = [1, 2, 3] const a = Array.of(1, 2, 3) const a = Array(6).fill(1) //   ,   6 ,  1 

Para acessar um elemento individual da matriz, use uma construção que consiste em colchetes que contêm o índice do elemento da matriz. Os elementos da matriz podem ser lidos ou gravados.

 const a = [1, 2, 3] console.log(a) //[ 1, 2, 3 ] const first = a[0] console.log(first) //1 a[0] = 4 console.log(a) //[ 4, 2, 3 ] 

O construtor Array para declarar matrizes não é recomendado.

 const a = new Array() //  const a = new Array(1, 2, 3) //  

Este método deve ser usado apenas ao declarar matrizes digitadas .

Et Obtendo o comprimento da matriz


Para descobrir o comprimento de uma matriz, você precisa se referir à sua propriedade length .

 const l = a.length 

HecConhecendo uma matriz usando o método every ()


O método every() matriz pode ser usado para organizar a verificação de todos os seus elementos usando uma determinada condição. Se todos os elementos da matriz atenderem à condição, a função retornará true , caso contrário, retornará false .

Esse método recebe uma função que recebe os argumentos currentValue (elemento atual da matriz), index (índice do elemento atual da matriz) e array (a própria matriz). Também pode levar um valor opcional, usado como this ao executar a função passada para ele.
Por exemplo, verifique se os valores de todos os elementos da matriz são maiores que 10.

 const a = [11, 12, 13] const b = [5, 6, 25] const test = el => el > 10 console.log(a.every(test)) //true console.log(b.every(test)) //false 

Aqui, na função test() , estamos interessados ​​apenas no primeiro argumento passado a ela, portanto, o declaramos, especificando apenas o parâmetro el , no qual o valor correspondente cairá.

HecConhecendo uma matriz usando o método some ()


Este método é muito semelhante ao método every() , mas retorna true se pelo menos um dos elementos da matriz satisfizer a condição especificada pela função transmitida a ele.

Crie uma matriz com base em uma matriz existente usando o método map ()


O método map() de matrizes permite iterar sobre matrizes, aplicando a cada elemento passado para esse método uma função que converte o elemento e cria novas matrizes a partir dos valores recebidos. Aqui, por exemplo, é como obter uma nova matriz, que é o resultado da multiplicação de todos os elementos da matriz original por 2.

 const a = [1, 2, 3] const double = el => el * 2 const doubleA = a.map(double) console.log(a) //[ 1, 2, 3 ] console.log(doubleA) //[ 2, 4, 6 ] 

▍ Filtrando uma matriz usando o método filter ()


O método filter() é semelhante ao método map() , mas permite criar novas matrizes que contêm apenas os elementos das matrizes originais que atendem à condição especificada pelo método filter() passado para a função.

▍ método reduzir ()


O método reduce() permite aplicar uma determinada função ao acumulador e a cada valor da matriz, reduzindo a matriz a um único valor (esse valor pode ter um tipo primitivo ou de objeto). Este método utiliza uma função de conversão e um valor inicial opcional da bateria. Considere um exemplo.

 const a = [1, 2, 3, 4].reduce((accumulator, currentValue, currentIndex, array) => { return accumulator * currentValue }, 1) console.log(a) //24 // 1: 1 * 1 = 1 // 2: 1 * 2 = 2 // 3: 2 * 3 = 6 // 4: 6 * 4 = 24 

Aqui, procuramos o produto de todos os elementos da matriz descritos usando um literal, configurando o valor inicial do acumulador 1.

Umer Enumerando uma matriz usando o método forEach ()


O método forEach() de matrizes pode ser usado para iterar sobre os valores de matrizes e executar determinadas ações nelas, especificadas pela função transmitida ao método. Por exemplo, exibimos, um de cada vez, os elementos da matriz no console.

 const a = [1, 2, 3] a.forEach(el => console.log(el)) //1 //2 //3 

Se você precisar interromper ou interromper o loop ao iterar sobre uma matriz, ao usar forEach() será necessário gerar uma exceção. Portanto, se, durante a solução de um determinado problema, for necessário interromper o ciclo, é melhor escolher outra maneira de iterar sobre os elementos da matriz.

▍ Selecionando uma matriz usando o operador for ...


O operador for...of apareceu no padrão ES6. Permite iterar sobre objetos iteráveis ​​(incluindo matrizes). Veja como usá-lo.

 const a = [1, 2, 3] for (let v of a) { console.log(v) } //1 //2 //3 

A cada iteração do loop, o próximo elemento da matriz a entra na variável v .

▍ Enumerando uma matriz usando a instrução for


A instrução for permite organizar loops, que, em particular, podem ser usados ​​para iterar sobre (ou inicializar) matrizes acessando seus elementos por índice. Normalmente, o índice do próximo elemento é obtido usando um contador de loop.

 const a = [1, 2, 3] for (let i = 0; i < a.length; i += 1) { console.log(a[i]) } //1 //2 //3 

Se, durante a execução do loop, você precisar pular sua iteração, poderá usar o comando continue . Para finalizar prematuramente o ciclo, você pode usar o comando break . Se você usar o comando return em um loop, por exemplo, localizado em uma determinada função, o loop e a função terminarão e o valor retornado com return irá para onde a função foi chamada.

▍ Método @@ iterator


Este método apareceu no padrão ES6. Ele permite que você obtenha o chamado "iterador de um objeto" - um objeto que, neste caso, permite organizar uma iteração dos elementos da matriz. Um iterador de matriz pode ser obtido usando o símbolo (esses símbolos são chamados de "símbolos conhecidos") Symbol.iterator . Após receber o iterador, você pode acessar o método next() , que, a cada chamada, retorna uma estrutura de dados que contém o próximo elemento da matriz.

 const a = [1, 2, 3] let it = a[Symbol.iterator]() console.log(it.next().value) //1 console.log(it.next().value) //2 console.log(it.next().value) //3 

Se você chamar o método next() depois que o último elemento da matriz for atingido, ele retornará, como o valor do elemento, undefined . O objeto retornado pelo método next() contém o value e as propriedades done . A propriedade done avalia como false até que o último elemento da matriz seja atingido. No nosso caso, se o chamarmos.next it.next() pela quarta vez, ele retornará o objeto { value: undefined, done: true } , enquanto nas três chamadas anteriores esse objeto se pareceria com { value: , done: false } .

O método da matriz entries() retorna um iterador que permite iterar sobre os pares de valores-chave da matriz.

 const a = [1, 2, 3] let it = a.entries() console.log(it.next().value) //[0, 1] console.log(it.next().value) //[1, 2] console.log(it.next().value) //[2, 3] 

O método keys() permite iterar sobre as chaves de uma matriz.

 const a = [1, 2, 3] let it = a.keys() console.log(it.next().value) //0 console.log(it.next().value) //1 console.log(it.next().value) //2 

▍Adicionando elementos ao final de uma matriz


Para adicionar elementos ao final da matriz, use o método push() .

 a.push(4) 

▍Adicionando elementos ao início da matriz


Para adicionar elementos ao início da matriz, use o método unshift() .

 a.unshift(0) a.unshift(-2, -1) 

Removendo elementos da matriz


Você pode remover um elemento do final da matriz enquanto retorna esse elemento usando o método pop() .

 a.pop() 

Da mesma forma, usando o método shift() , você pode remover um elemento do início da matriz.

 a.shift() 

A mesma coisa, mas já indicando a posição da remoção dos elementos e seu número, é feita usando o método splice() .

 a.splice(0, 2) //    2     a.splice(3, 2) //    2 ,    3 

EmRemovendo elementos da matriz e inserindo outros elementos


Para usar alguma operação para remover alguns elementos da matriz e inserir outros elementos, o método splice() familiar é usado.

Por exemplo, aqui excluímos 3 elementos da matriz começando no índice 2, após o qual adicionamos outros dois elementos ao mesmo local:

 const a = [1, 2, 3, 4, 5, 6] a.splice(2, 3, 'a', 'b') console.log(a) //[ 1, 2, 'a', 'b', 6 ] 

Combinar várias matrizes


Para combinar várias matrizes, você pode usar o método concat() , que retorna uma nova matriz.

 const a = [1, 2] const b = [3, 4] const c = a.concat(b) console.log(c) //[ 1, 2, 3, 4 ] 

▍Encontre itens em uma matriz


No padrão ES5, o método indexOf() apareceu, que retorna o índice da primeira ocorrência do elemento de matriz desejado. Se o elemento não puder ser encontrado na matriz, -1 será retornado.

 const a = [1, 2, 3, 4, 5, 6, 7, 5, 8] console.log(a.indexOf(5)) //4 console.log(a.indexOf(23)) //-1 

O método lastIndexOf() retorna o índice da última ocorrência do elemento na matriz ou -1 se o elemento não for encontrado.

 const a = [1, 2, 3, 4, 5, 6, 7, 5, 8] console.log(a.lastIndexOf(5)) //7 console.log(a.lastIndexOf(23)) //-1 

No ES6, o método find() de matrizes apareceu, que executa uma pesquisa de matriz usando a função transmitida a ela. Se a função retornar true , o método retornará o valor do primeiro elemento encontrado. Se o item não puder ser encontrado, a função retornará undefined .

Seu uso pode parecer da seguinte maneira.

 a.find(x => x.id === my_id) 

Aqui, em uma matriz que contém objetos, é procurado um elemento cuja propriedade id seja igual à especificada.

O método findIndex() é semelhante ao find() , mas retorna o índice do elemento encontrado ou undefined .

O método includes() apareceu no ES7, o que permite verificar a presença de um determinado elemento em uma matriz. Retorna true ou false , localizando ou não um elemento de interesse do programador.

 a.includes(value) 

Usando esse método, é possível verificar a presença de algum elemento, não a matriz inteira, mas apenas parte dela, começando com o índice especificado quando esse método foi chamado. O índice é especificado usando o segundo parâmetro opcional deste método.

 a.includes(value, i) 

Et Obtendo um fragmento de uma matriz


Para obter uma cópia de algum fragmento da matriz como uma nova matriz, você pode usar o método slice() . Se esse método for chamado sem argumentos, a matriz retornada será uma cópia completa do original. São necessários dois parâmetros opcionais. O primeiro define o índice inicial do fragmento, o segundo define o final. Se o índice final não for especificado, a matriz será copiada do índice inicial especificado para o final.

 const a = [1, 2, 3, 4, 5, 6, 7, 8, 9] console.log(a.slice(4)) //[ 5, 6, 7, 8, 9 ] console.log(a.slice(3,7)) //[ 4, 5, 6, 7 ] 

ArrayOrdenar matriz


Para organizar a classificação dos elementos da matriz em ordem alfabética ( 0-9A-Za-z ), o método sort() é usado sem passar argumentos para ele.

 const a = [1, 2, 3, 10, 11] a.sort() console.log(a) //[ 1, 10, 11, 2, 3 ] const b = [1, 'a', 'Z', 3, 2, 11] b.sort() console.log(b) //[ 1, 11, 2, 3, 'Z', 'a' ] 

Você pode passar uma função para esse método que define a ordem de classificação. A função aceita, para comparação de dois elementos, os parâmetros a e b . Retorna um número negativo se a menor que b por algum critério, 0 se eles forem iguais e um número positivo se a maior que b . Ao escrever uma função semelhante para classificar matrizes numéricas, ela pode retornar o resultado da subtração a e b . Portanto, retornar o resultado da avaliação da expressão a - b significa classificar a matriz em ordem crescente, retornando o resultado da avaliação da expressão b - a classificará a matriz em ordem decrescente.

 const a = [1, 10, 3, 2, 11] console.log(a.sort((a, b) => a - b)) //[ 1, 2, 3, 10, 11 ] console.log(a.sort((a, b) => b - a)) //[ 11, 10, 3, 2, 1 ] 

Para reverter a sequência de elementos da matriz, você pode usar o método reverse() . Assim como sort() , modifica a matriz para a qual é chamada.

Obtendo uma representação de string de uma matriz


Para obter uma representação de string de uma matriz, você pode usar o toString() .

 a.toString() 

Um resultado semelhante é dado pelo método join() , chamado sem argumentos.

 a.join() 

Para isso, como argumento, você pode passar os elementos separadores.

 const a = [1, 10, 3, 2, 11] console.log(a.toString()) //1,10,3,2,11 console.log(a.join()) //1,10,3,2,11 console.log(a.join(', ')) //1, 10, 3, 2, 11 

ReatCriando cópias de matrizes


Para criar uma cópia da matriz, copiando os valores da matriz original para a nova matriz, você pode usar o método Array.from() . Também é adequado para criar matrizes a partir de objetos do tipo matriz (a partir de strings, por exemplo).

 const a = 'a string' const b = Array.from(a) console.log(b) //[ 'a', ' ', 's', 't', 'r', 'i', 'n', 'g' ] 

O método Array.of() também pode ser usado para copiar matrizes, bem como para "montar" matrizes de vários elementos. Por exemplo, para copiar os elementos de uma matriz para outra, você pode usar a seguinte construção.

 const a = [1, 10, 3, 2, 11] const b = Array.of(...a) console.log(b) // [ 1, 10, 3, 2, 11 ] 

O método copyWithin() é usado para copiar os elementos da matriz para um determinado local dessa matriz. Seu primeiro argumento especifica o índice inicial da posição de destino, o segundo o índice inicial da posição da fonte do elemento e o terceiro parâmetro, opcional, indica o índice final da posição da fonte do elemento. Se você não especificar, tudo será copiado para o local especificado da matriz, iniciando do índice inicial da posição de origem até o final da matriz.

 const a = [1, 2, 3, 4, 5] a.copyWithin(0, 2) console.log(a) //[ 3, 4, 5, 4, 5 ] 

Ciclos


Falando sobre arrays acima, já encontramos algumas maneiras de organizar loops. No entanto, loops em JavaScript são usados ​​não apenas para trabalhar com matrizes, e consideramos longe de todos os seus tipos. Portanto, agora dedicaremos algum tempo para discutir diferentes maneiras de organizar loops em JavaScript e falar sobre seus recursos.

▍ para loop


Considere um exemplo de aplicação desse ciclo.

 const list = ['a', 'b', 'c'] for (let i = 0; i < list.length; i++) { console.log(list[i]) //,     console.log(i) // } 

Como já mencionado, você pode interromper a execução de um loop usando o comando break e pode pular a iteração atual e ir diretamente para a próxima usando o comando continue .

▍ para cada ciclo


Também discutimos esse ciclo. Aqui está um exemplo de iteração sobre uma matriz usando-a.

 const list = ['a', 'b', 'c'] list.forEach((item, index) => { console.log(item) // console.log(index) // }) //     ,      list.forEach(item => console.log(item)) 

Lembre-se de que para interromper esse ciclo, é necessário lançar uma exceção, ou seja, se você precisar interrompê-lo ao usar um ciclo, é melhor escolher outro ciclo.

▍ Faça ... while loop


Este é o chamado "ciclo pós-condição". Esse loop será executado pelo menos uma vez antes de verificar a condição para finalizar o loop.

 const list = ['a', 'b', 'c'] let i = 0 do { console.log(list[i]) // console.log(i) // i = i + 1 } while (i < list.length) 

Ele pode ser interrompido usando o comando break , você pode prosseguir para a próxima iteração com o comando continue .

▍ loop enquanto


Este é o chamado "ciclo pré-condicionado". Se, na entrada do ciclo, a condição para continuar o ciclo for falsa, ela não será executada nem uma vez.

 const list = ['a', 'b', 'c'] let i = 0 while (i < list.length) { console.log(list[i]) // console.log(i) // i = i + 1 } 

▍ para ... em loop


Esse loop permite iterar todas as propriedades enumeradas de um objeto por seus nomes.

 let object = {a: 1, b: 2, c: 'three'} for (let property in object) { console.log(property) //  console.log(object[property]) //  } 

▍ Ciclo para ... de


O ciclo for...of combina a conveniência do ciclo forEach e a capacidade de interromper sua operação usando ferramentas regulares.

 //  for (const value of ['a', 'b', 'c']) { console.log(value) // } //       `entries()` for (const [index, value] of ['a', 'b', 'c'].entries()) { console.log(index) // console.log(value) // } 

Observe que aqui, no cabeçalho do loop, a palavra-chave const é usada e não, como você pode esperar, let . Se as variáveis ​​dentro do bloco de loop não precisarem ser redesignadas, const é bastante adequado para nós.
Se compararmos os loops for...in e for...of , verifica-se que for...in itera sobre os nomes das propriedades e for...of - valores das propriedades.

Loops e escopos


Com loops e escopos variáveis, há um recurso JavaScript que pode causar problemas ao desenvolvedor. Para lidar com esses problemas, let falar sobre loops, escopos e palavras-chave var e let .

Considere um exemplo.

 const operations = [] for (var i = 0; i < 5; i++) { operations.push(() => {   console.log(i) }) } for (const operation of operations) { operation() } 

O loop executa 5 iterações, em cada uma das quais uma nova função é adicionada à matriz de operations . Esta função exibe no console o valor do contador de loops - i . Depois que as funções são adicionadas à matriz, iteramos sobre essa matriz e chamamos as funções que são seus elementos.

Ao executar esse código, você pode esperar o resultado mostrado abaixo.

 0 1 2 3 4 

Mas, de fato, ele deduz o seguinte.

 5 5 5 5 5 

Por que isso é assim? O fato é que, como contador de loop, usamos uma variável declarada usando a palavra-chave var .

Como as declarações dessas variáveis ​​vão para o topo do escopo, o código acima é semelhante ao seguinte.

 var i; const operations = [] for (i = 0; i < 5; i++) { operations.push(() => {   console.log(i) }) } for (const operation of operations) { operation() } 

Como resultado, verifica-se que no loop for...of , no qual iteramos sobre a matriz, a variável i ainda é visível, é 5, como resultado, referindo-se a i em todas as funções, imprimimos o número 5.

Como mudar o comportamento do programa para que ele faça o que é esperado dele?

A solução mais simples para esse problema é usar a palavra-chave let . Como já dissemos, apareceu no ES6, seu uso permite que você se livre de algumas curiosidades características do var .

Em particular, no exemplo acima, basta alterar var para let e tudo funcionará como deveria.

 const operations = [] for (let i = 0; i < 5; i++) { operations.push(() => {   console.log(i) }) } for (const operation of operations) { operation() } 

Agora, a cada iteração do loop, cada função adicionada à matriz de operations obtém sua própria cópia de i . Lembre-se de que, nessa situação, você não pode usar a palavra-chave const , pois o valor de i no loop muda.

Outra maneira de resolver esse problema, que costumava ser usado antes do padrão ES6, quando a palavra-chave let não estava lá, era usar o IIFE.

Com essa abordagem, o valor de i armazenado no fechamento, e a função retornada pelo IIFE e tendo acesso ao fechamento entra na matriz. Esta função pode ser executada quando necessário. Aqui está como fica.

 const operations = [] for (var i = 0; i < 5; i++) { operations.push(((j) => {   return () => console.log(j) })(i)) } for (const operation of operations) { operation() } 

Sumário


Hoje falamos sobre matrizes e loops em JavaScript. O tópico de nosso próximo artigo é manipulação de exceções, padrões de uso de ponto e vírgula e literais de modelo.

Caros leitores! Quais métodos para trabalhar com matrizes em JavaScript você usa com mais frequência?

Source: https://habr.com/ru/post/pt430380/


All Articles