Apresentamos a vocĂȘ a tradução de um artigo de Thomas Lombart, publicado em medium.freecodecamp.org. A tradução Ă© publicada com permissĂŁo do autor.
Um exemplo de uso do mĂ©todo de redução para reduzir uma matrizDeixe-me fazer uma declaração ousada: os loops geralmente sĂŁo inĂșteis e dificultam a leitura do cĂłdigo. Para iteraçÔes em matrizes, pesquisa, classificação de elementos e outras açÔes semelhantes, vocĂȘ pode usar um dos mĂ©todos abaixo.
Apesar da eficĂĄcia, a maioria desses mĂ©todos ainda Ă© pouco conhecida e pouco popular. Farei o trabalho duro por vocĂȘ e falarei sobre os mais Ășteis. Leia este artigo como seu guia para mĂ©todos de matriz JavaScript.
Nota : Antes de começarmos, vocĂȘ precisa saber uma coisa: sou inclinado para a programação funcional. Para evitar efeitos colaterais, eu me esforço para aplicar mĂ©todos que nĂŁo modificam diretamente a matriz original. NĂŁo estou dizendo para vocĂȘ se recusar a alterar a matriz, mas vale a pena considerar que alguns mĂ©todos levam a isso. Como resultado, efeitos colaterais, alteraçÔes indesejadas e, como resultado, erros aparecem.
Este artigo foi publicado originalmente em
thomlom.dev , onde vocĂȘ pode encontrar mais material de desenvolvimento da Web.
O bĂĄsico
Existem quatro mĂ©todos que vale a pena saber se vocĂȘ estiver trabalhando com matrizes. Estes sĂŁo
map
,
filter
,
reduce
e o operador de
spread
. Eles sĂŁo eficazes e Ășteis.
mapaVocĂȘ costuma usar o mĂ©todo de
map
. Em geral, sempre que precisar alterar os elementos de uma matriz, considere esta opção.
à necessårio um parùmetro - uma função que é chamada em cada elemento da matriz e, em seguida, retorna uma
nova matriz para que nĂŁo haja efeitos colaterais.
const numbers = [1, 2, 3, 4] const numbersPlusOne = numbers.map(n => n + 1) console.log(numbersPlusOne)
VocĂȘ tambĂ©m pode criar uma nova matriz que armazena apenas uma propriedade especĂfica do objeto.
const allActivities = [ { title: 'My activity', coordinates: [50.123, 3.291] }, { title: 'Another activity', coordinates: [1.238, 4.292] } ] const allCoordinates = allActivities.map(activity => activity.coordinates) console.log(allCoordinates)
Portanto, lembre-se: quando precisar
alterar uma matriz, pense em usar o
mapa .
filtrarO nome desse método fala por si: use-o quando desejar filtrar uma matriz.
Como o
map
, o
filter
usa como Ășnico parĂąmetro uma função que Ă© chamada em cada elemento da matriz. Esta função deve retornar um valor booleano:
true
- se vocĂȘ deseja salvar o elemento em uma matriz;false
- se vocĂȘ nĂŁo quiser salvĂĄ-lo.
Como resultado, vocĂȘ terĂĄ a nova matriz correta com os elementos que deseja deixar.
Por exemplo, apenas nĂșmeros Ămpares podem ser armazenados em uma matriz.
const numbers = [1, 2, 3, 4, 5, 6] const oddNumbers = numbers.filter(n => n % 2 !== 0) console.log(oddNumbers)
VocĂȘ tambĂ©m pode usar o filtro para remover um elemento especĂfico da matriz.
const participants = [ { id: 'a3f47', username: 'john' }, { id: 'fek28', username: 'mary' }, { id: 'n3j44', username: 'sam' }, ] function removeParticipant(participants, id) { return participants.filter(participant => participant.id !== id) } console.log(removeParticipant(participants, 'a3f47'))
reduzirNa minha opiniĂŁo, esse mĂ©todo Ă© o mais difĂcil de entender. Mas assim que dominĂĄ-lo, vocĂȘ terĂĄ vĂĄrias oportunidades.
Normalmente, o método de
reduce
pega uma matriz de valores e concatena-os em um Ășnico valor. SĂŁo necessĂĄrios dois parĂąmetros, uma função de retorno de chamada (que Ă© o
redutor ) e um valor inicial opcional (que Ă© o primeiro elemento da matriz por padrĂŁo). A caixa de engrenagens possui quatro parĂąmetros:
- uma bateria que coleta os valores retornados na caixa de velocidades ;
- valor atual da matriz;
- Ăndice atual;
- a matriz para a qual o método de
reduce
foi chamado.
Basicamente, vocĂȘ usarĂĄ apenas os dois primeiros parĂąmetros - a bateria e o valor atual.
Mas não vamos aprofundar a teoria e considerar o exemplo mais comum de aplicação de
reduce
.
const numbers = [37, 12, 28, 4, 9] const total = numbers.reduce((total, n) => total + n) console.log(total)
Na primeira iteração, o acumulador, que é a soma, assume o valor inicial 37. O valor retornado é 37 + n, onde n = 12. Obtemos 49.
Durante a segunda iteração, o acumulador é 49, o valor retornado é 49 + 28 = 77. E assim por diante.
O método de
reduce
Ă© tĂŁo funcional que vocĂȘ pode usĂĄ-lo para criar muitos mĂ©todos de matriz, como
map
ou
filter
.
const map = (arr, fn) => { return arr.reduce((mappedArr, element) => { return [...mappedArr, fn(element)] }, []) } console.log(map([1, 2, 3, 4], n => n + 1))
Como regra, atribuĂmos o valor inicial
[]
ao método de
reduce
- o acumulador. Para o
map
executamos uma função cujo resultado é adicionado ao final da bateria usando
o operador spread (falaremos sobre isso abaixo, nĂŁo se preocupe). Para o
filter
fazendo quase a mesma coisa, apenas executamos a função de filtro no elemento. Se for verdade, retornamos a matriz
anterior . Caso contrĂĄrio, adicione o elemento ao final da matriz.
Vejamos um exemplo mais complexo: reduza muito o array
[1, 2, 3, [4, [[[5, [6, 7]]]], 8]]
para
[1, 2, 3, 4, 5, 6, 7, 8]
.
function flatDeep(arr) { return arr.reduce((flattenArray, element) => { return Array.isArray(element) ? [...flattenArray, ...flatDeep(element)] : [...flattenArray, element] }, []) } console.log(flatDeep([1, 2, 3, [4, [[[5, [6, 7]]]], 8]]))
Este exemplo Ă© muito semelhante ao
map
, exceto pelo fato de usarmos recursĂŁo aqui. NĂŁo vou me deter na recursĂŁo em detalhes, porque isso estĂĄ alĂ©m do escopo de nosso tĂłpico, mas se vocĂȘ quiser saber mais, acesse este
excelente recurso .
Declaração de spread (ES2015)Eu concordo, este nĂŁo Ă© um mĂ©todo. No entanto, o operador de spread ajuda a atingir objetivos diferentes ao trabalhar com matrizes. VocĂȘ pode aplicĂĄ-lo para expandir os valores de uma matriz em outra e, em seguida, fazer uma cĂłpia ou vincular vĂĄrias matrizes.
const numbers = [1, 2, 3] const numbersCopy = [...numbers] console.log(numbersCopy)
Nota : a declaração de spread faz uma
cĂłpia superficial da matriz original. Mas o que significa "superficial"?
Essa cĂłpia duplicarĂĄ os elementos originais o mĂnimo possĂvel. Se vocĂȘ tiver uma matriz com nĂșmeros, seqĂŒĂȘncias de caracteres ou valores booleanos (
tipos primitivos ), nĂŁo haverĂĄ problemas e os valores serĂŁo realmente duplicados. No entanto, as coisas sĂŁo diferentes com
objetos e
matrizes : apenas uma
referĂȘncia ao valor original Ă© copiada. Portanto, se vocĂȘ fizer uma cĂłpia superficial da matriz, incluindo o objeto e alterar o objeto na matriz copiada, ela tambĂ©m serĂĄ alterada no original, porque eles tĂȘm a
mesma referĂȘncia .
const arr = ['foo', 42, { name: 'Thomas' }] let copy = [...arr] copy[0] = 'bar' console.log(arr)
Portanto, se vocĂȘ quiser criar uma cĂłpia real de uma matriz que contenha um objeto ou matrizes, poderĂĄ usar uma função
lodash como
cloneDeep . Mas nĂŁo se considere obrigado a fazer isso. Seu objetivo Ă©
descobrir como tudo funciona sob o capĂŽ .
MĂ©todos Ășteis
Abaixo, vocĂȘ encontrarĂĄ outros mĂ©todos que tambĂ©m sĂŁo Ășteis e que podem ser Ășteis para solucionar problemas, como encontrar um elemento em uma matriz, remover parte de uma matriz e muito mais.
inclui (ES2015)VocĂȘ jĂĄ usou o
indexOf
para descobrir se hĂĄ um elemento em uma matriz ou nĂŁo? Uma maneira terrĂvel de verificar, certo?
Felizmente, o método
includes
faz a validação para nós. Defina o parùmetro para includes e ele procurarå o elemento na matriz.
const sports = ['football', 'archery', 'judo'] const hasFootball = sports.includes('football') console.log(hasFootball)
concatO método concat pode ser usado para mesclar duas ou mais matrizes.
const numbers = [1, 2, 3] const otherNumbers = [4, 5, 6] const numbersConcatenated = numbers.concat(otherNumbers) console.log(numbersConcatenated)
forEachSe vocĂȘ deseja executar uma ação para cada elemento da matriz, pode usar o mĂ©todo
forEach
. Ele assume uma função como parĂąmetro, que por sua vez tambĂ©m aceita trĂȘs parĂąmetros: valor atual, Ăndice e matriz.
const numbers = [1, 2, 3, 4, 5] numbers.forEach(console.log)
indexOfEste mĂ©todo Ă© usado para retornar o primeiro Ăndice no qual o elemento pode ser encontrado na matriz. AlĂ©m disso, o
indexOf
frequentemente verifica a presença de um elemento em uma matriz. Honestamente, agora eu o uso com pouca frequĂȘncia.
const sports = ['football', 'archery', 'judo'] const judoIndex = sports.indexOf('judo') console.log(judoIndex)
encontrarO método
find
Ă© semelhante ao
filter
. VocĂȘ precisa fornecĂȘ-lo com uma função que testa cada elemento da matriz. No entanto, o
find
para de testar os itens assim que encontrar um que passou no teste. Este
nĂŁo Ă©
um filter
que itera por toda a matriz, independentemente das circunstĂąncias.
const users = [ { id: 'af35', name: 'john' }, { id: '6gbe', name: 'mary' }, { id: '932j', name: 'gary' }, ] const user = users.find(user => user.id === '6gbe') console.log(user)
Portanto, use o método
filter
quando desejar filtrar
toda a matriz e o método
find
quando tiver certeza de que estĂĄ procurando um elemento
exclusivo na matriz.
findIndexEste método é quase o mesmo que
find
, mas retorna o Ăndice do primeiro elemento encontrado em vez do prĂłprio elemento.
const users = [ { id: 'af35', name: 'john' }, { id: '6gbe', name: 'mary' }, { id: '932j', name: 'gary' }, ] const user = users.findIndex(user => user.id === '6gbe') console.log(user)
VocĂȘ pode pensar que
findIndex
e
indexOf
sĂŁo a mesma coisa. Na verdade nĂŁo. O primeiro parĂąmetro de
indexOf
Ă© um valor primitivo (um valor booleano, nĂșmero, sequĂȘncia, valor indefinido ou caractere), enquanto o primeiro parĂąmetro,
findIndex
é uma função de retorno de chamada.
Portanto, quando vocĂȘ precisar encontrar o Ăndice de um elemento em uma matriz de valores primitivos, poderĂĄ trabalhar com
indexOf
. Se vocĂȘ tiver elementos mais complexos, como objetos, use
findIndex
.
fatiaQuando vocĂȘ precisar participar de uma matriz ou copiar uma matriz, pode consultar o mĂ©todo de
slice
. Mas tenha cuidado: como o operador de propagação, a
slice
retorna uma
cĂłpia superficial .
const numbers = [1, 2, 3, 4, 5] const copy = numbers.slice()
No começo do artigo, mencionei que os loops geralmente sĂŁo inĂșteis. Deixe-me mostrar como se livrar deles.
Suponha que vocĂȘ deseje retornar um certo nĂșmero de mensagens de bate-papo da API e vocĂȘ sĂł precisarĂĄ ver cinco delas. Abaixo estĂŁo duas abordagens: uma com loops e outra com o mĂ©todo de
slice
.
algunsSe vocĂȘ deseja verificar se
pelo menos um elemento da matriz passa no teste, vocĂȘ pode usar
some
. Como
map
,
filter
ou
find
, o método
some
recebe uma função de retorno de chamada como o Ășnico parĂąmetro e retorna
true
se pelo menos um elemento passa na verificação e
false
se nĂŁo.
some
também são adequados para trabalhar com permissÔes.
const users = [ { id: 'fe34', permissions: ['read', 'write'], }, { id: 'a198', permissions: [], }, { id: '18aa', permissions: ['delete', 'read', 'write'], } ] const hasDeletePermission = users.some(user => user.permissions.includes('delete') ) console.log(hasDeletePermission)
todoEste método é semelhante a
some
, exceto pelo fato de verificar se
cada elemento (e
não um ) corresponde à condição.
const users = [ { id: 'fe34', permissions: ['read', 'write'], }, { id: 'a198', permissions: [], }, { id: '18aa', permissions: ['delete', 'read', 'write'], } ] const hasAllReadPermission = users.every(user => user.permissions.includes('read') ) console.log(hasAllReadPermission)
plano (ES2019)Estes são métodos completamente novos no mundo do JavaScript. Normalmente,
flat
cria uma nova matriz, conectando todos os elementos de uma matriz aninhada. Ă preciso um parĂąmetro - um nĂșmero que indica quanto vocĂȘ deseja reduzir a dimensĂŁo da matriz.
const numbers = [1, 2, [3, 4, [5, [6, 7]], [[[[8]]]]]] const numbersflattenOnce = numbers.flat() console.log(numbersflattenOnce)
flatMap (ES2019)Adivinha o que esse mĂ©todo faz? Aposto que vocĂȘ entenderĂĄ um nome.
Primeiro, ele executa a função de mapeamento para cada elemento e reduz a matriz de cada vez. Simples assim!
const sentences = [ 'This is a sentence', 'This is another sentence', "I can't find any original phrases", ] const allWords = sentences.flatMap(sentence => sentence.split(' ')) console.log(allWords)
Neste exemplo, vocĂȘ tem muitas frases na matriz e deseja obter todas as palavras. Em vez de usar o mĂ©todo de
map
e dividir todas as frases em palavras e encurtar a matriz, vocĂȘ pode usar o
flatMap
.
Depois, vocĂȘ pode contar o nĂșmero de palavras com a função
reduce
(isso nĂŁo se aplica ao
flatMap
, só quero lhe mostrar outro exemplo usando o método
reduce
).
const wordsCount = allWords.reduce((count, word) => { count[word] = count[word] ? count[word] + 1 : 1 return count }, {}) console.log(wordsCount)
O método
flatMap
também
flatMap
frequentemente usado em programação reativa. VocĂȘ pode ver um exemplo
aqui .
juntarSe vocĂȘ precisar criar uma string com base nos elementos da matriz, o mĂ©todo
join
serĂĄ o que vocĂȘ precisa. Permite criar uma nova linha conectando todos os elementos da matriz, separados pelo separador fornecido.
Por exemplo, usando a
join
vocĂȘ pode exibir visualmente todos os participantes de uma atividade.
const participants = ['john', 'mary', 'gary'] const participantsFormatted = participants.join(', ') console.log(participantsFormatted)
E este Ă© um exemplo mais realista, onde vocĂȘ pode primeiro filtrar os participantes e obter seus nomes.
const potentialParticipants = [ { id: 'k38i', name: 'john', age: 17 }, { id: 'baf3', name: 'mary', age: 13 }, { id: 'a111', name: 'gary', age: 24 }, { id: 'fx34', name: 'emma', age: 34 }, ] const participantsFormatted = potentialParticipants .filter(user => user.age > 18) .map(user => user.name) .join(', ') console.log(participantsFormatted)
deEste é um método
estĂĄtico que cria uma nova matriz a partir de um objeto iterĂĄvel ou semelhante a uma matriz, como uma string. Pode ser Ăștil quando vocĂȘ trabalha com o modelo de objeto do documento.
const nodes = document.querySelectorAll('.todo-item')
VocĂȘ viu que usamos um tipo de matriz em vez de uma instĂąncia de matriz? Ă por isso que esse mĂ©todo Ă© chamado estĂĄtico.
EntĂŁo vocĂȘ pode se divertir com os nĂłs, por exemplo, registrando ouvintes de eventos para cada um deles usando o mĂ©todo
forEach
.
todoItems.forEach(item => { item.addEventListener('click', function() { alert(`You clicked on ${item.innerHTML}`) }) })
Modificação de matriz que vale a pena conhecer
A seguir estĂŁo outros mĂ©todos padrĂŁo. A diferença deles Ă© que eles modificam a matriz original. NĂŁo hĂĄ nada errado com a alteração, mas vocĂȘ deve considerar isso ao trabalhar.
Se vocĂȘ nĂŁo deseja modificar a matriz original enquanto trabalha com esses mĂ©todos, faça uma cĂłpia de superfĂcie ou completa com antecedĂȘncia.
const arr = [1, 2, 3, 4, 5] const copy = [...arr]
ordenarSim, a
sort
modifica a matriz original. De fato, ele classifica os elementos da matriz no lugar. O mĂ©todo de classificação padrĂŁo transforma todos os elementos em seqĂŒĂȘncias de caracteres e os classifica em ordem alfabĂ©tica.
const names = ['john', 'mary', 'gary', 'anna'] names.sort() console.log(names)
Cuidado: se vocĂȘ, por exemplo, mudou da linguagem Python, o mĂ©todo de
sort
ao trabalhar com uma matriz de nĂșmeros nĂŁo fornecerĂĄ o resultado desejado.
const numbers = [23, 12, 17, 187, 3, 90] numbers.sort() console.log(numbers)
Como então classificar uma matriz? O método de
sort
assume uma função -
uma função de comparação . São necessårios dois parùmetros: o primeiro elemento (
) e o segundo elemento para comparação (
b
). Uma comparação entre esses dois elementos requer que um dĂgito seja retornado:
- se o valor for negativo -
a
classificado antes de b
; - se o valor for positivo,
b
classificado antes de a
; - se o valor for 0, nenhuma alteração.
EntĂŁo vocĂȘ pode classificar os nĂșmeros.
const numbers = [23, 12, 17, 187, 3, 90] numbers.sort((a, b) => a - b) console.log(numbers)
Ou vocĂȘ pode classificar as datas das mais recentes.
const posts = [ { title: 'Create a Discord bot under 15 minutes', date: new Date(2018, 11, 26), }, { title: 'How to get better at writing CSS', date: new Date(2018, 06, 17) }, { title: 'JavaScript arrays', date: new Date() }, ] posts.sort((a, b) => a.date - b.date)
preencherO método de
fill
modifica ou preenche todos os elementos da matriz do Ăndice inicial atĂ© o final com o valor especificado. Um exemplo do excelente uso do
fill
Ă© preencher uma nova matriz com dados iniciais.
inverterParece-me que o nome do mĂ©todo explica completamente sua essĂȘncia.
const numbers = [1, 2, 3, 4, 5] numbers.reverse() console.log(numbers)
popEste mĂ©todo remove o Ășltimo elemento da matriz e o retorna.
const messages = ['Hello', 'Hey', 'How are you?', "I'm fine"] const lastMessage = messages.pop() console.log(messages)
MĂ©todos que podem ser substituĂdos
Na Ășltima seção, vocĂȘ encontrarĂĄ mĂ©todos que modificam a matriz original e sĂŁo fĂĄceis de encontrar uma alternativa. NĂŁo estou dizendo que eles precisam ser descontados, apenas quero transmitir a vocĂȘ que alguns mĂ©todos tĂȘm efeitos colaterais e podem ser substituĂdos.
empurrarEste mĂ©todo Ă© usado com freqĂŒĂȘncia. Ele permite adicionar um ou mais elementos Ă matriz e criar uma nova matriz com base na matriz anterior.
const todoItems = [1, 2, 3, 4, 5] const itemsIncremented = [] for (let i = 0; i < items.length; i++) { itemsIncremented.push(items[i] + 1) } console.log(itemsIncremented)
Se vocĂȘ precisar criar uma matriz com base em outra, como no mĂ©todo
itemsIncremented
, existem
map
,
filter
ou
itemsIncremented
adequados que jĂĄ nos sĂŁo familiares. Por exemplo, podemos pegar um
map
para fazer isso.
const itemsIncremented = todoItems.map(x => x + 1)
E se vocĂȘ deseja usar
push
quando precisar adicionar um novo elemento, o operador de propagação Ă© Ăștil.
const todos = ['Write an article', 'Proofreading'] console.log([...todos, 'Publish the article'])
emendasplice
frequentemente acessada para limpar um elemento em um Ăndice especĂfico. VocĂȘ pode fazer o mesmo com o mĂ©todo de
filter
.
const months = ['January', 'February', 'March', 'April', ' May']
VocĂȘ pode perguntar: e se eu precisar remover muitos elementos? EntĂŁo use
slice
.
const months = ['January', 'February', 'March', 'April', ' May']
mudançaO método
shift
remove o primeiro elemento da matriz e o retorna. Para fazer isso no estilo de programação funcional, vocĂȘ pode usar a instrução spread ou rest.
const numbers = [1, 2, 3, 4, 5]
deslocarO mĂ©todo unshift permite adicionar um ou mais elementos ao inĂcio de uma matriz. Como no
shift
, vocĂȘ pode fazer isso com o operador de spread.
const numbers = [3, 4, 5]
TL; DR
- Quando vocĂȘ deseja executar algumas operaçÔes com uma matriz, nĂŁo use o loop for e nĂŁo reinvente a roda, porque provavelmente existe um mĂ©todo acima que pode fazer o que vocĂȘ precisa.
- Na maioria das vezes, vocĂȘ usarĂĄ o
map
, filter
, reduce
métodos e o operador de propagação - essas são ferramentas importantes para qualquer desenvolvedor. - Também existem muitos métodos de matriz que seria bom saber:
slice
, some
, flatMap
, etc. Conheça-os e aplique-os, se necessårio. - Os efeitos colaterais podem levar a alteraçÔes indesejadas. Lembre-se de que alguns métodos modificam sua matriz original.
- O método de
slice
e o operador de propagação fazem cĂłpias rasas. Como resultado, objetos e sub-matrizes terĂŁo os mesmos links - isso tambĂ©m vale a pena ter em mente. - MĂ©todos antigos que modificam a matriz podem ser substituĂdos por novos. VocĂȘ decide o que fazer.
Agora vocĂȘ sabe tudo o que deve saber sobre matrizes JavaScript. Se vocĂȘ gostou
deste artigo , clique no botão "Pat" (até 50 vezes, se quiser :-)) e compartilhe-o. E fique à vontade para compartilhar suas impressÔes nos comentårios!