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)
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)
O construtor
Array
para declarar matrizes não é recomendado.
const a = new Array()
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))
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)
▍ 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)
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))
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) }
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]) }
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)
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)
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)
▍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)
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)
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)
▍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))
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))
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))
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)
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))
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())
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)
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)
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)
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])
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)
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])
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])
▍ 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)
▍ 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.
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?
