No nosso artigo anterior exploramos como as diferenças entre os métodos de arrays, dizendo que eles podem ser úteis no dia-a-dia, entretanto não nos aprofundamos muito em detalhes para nenhum deles, por isso hoje vamos ver 5 dicas para você parar de usar o map só naqueles exemplos de incrementar os números de um array!
# 01 - Usar para fazer o cast de tipo
Para a nossa primeira dica vamos ver como podemos usar o map para rapidamente converter todos os valores de um array para determinado tipo. Para isso podemos usar os construtores dos valores primitivos do JS: String, Number, e Boolean.
Eles são funções também, e por isso podem ser utilizados para converter os valores de um array no tipo correspondente, ex:
const numbers = [1, 2, 3];
const strings = numbers.map(String);
const numbersAgain = strings.map(Number);
const booleans = numbersAgain.map(Boolean);
# 02 - Usar para aplicar um Adapter em um array de objetos
Podemos usar ele em um array de objetos em favor de pegar só uma propriedade em específico, ex:
const people = [
{ name: 'John Doe', age: 20 },
{ name: 'Jane Doe', age: 22 },
{ name: 'Fulano de Tal', age: 18 }
];
const names = people.map(({ name }) => name);
Um conjunto delas:
const people = [
{ name: 'John Doe', age: 20, country: 'USA' },
{ name: 'Jane Doe', age: 22, country: 'USA' },
{ name: 'Fulano de Tal', age: 18, country: 'Brazil' }
];
const namesAndAges = people.map(({ name, age }) => ({
name,
age
}));
Ou aplicar o padrão de projetos adapter em si:
class Post {
constructor(title, content) {
this.title = title;
this.content = content;
}
}
class ApiPostAdapter extends Post {
constructor(apiPost) {
super(apiPost.title, apiPost.body);
}
static from(apiPost) {
return new ApiPostAdapter(apiPost);
}
}
fetch("api/posts")
.then(response => response.json())
.then(posts => posts.map(ApiPostAdapter.from));
Assim sendo uma ferramenta bem útil para manipular as informações de um objeto, adaptando elas para cada formato que for sendo necessário na aplicação, o que é particularmente útil quando você tem que traduzir entre objetos e DTOs, por exemplo, ao ter que adaptar os dados do banco de dados em um objeto de domínio, e transformar os objetos de domínio em view models que serão utilizados pelas views do seu sistema.
# 03 - Atualizar um valor no array
Podemos usar o map para atualizar um valor em específico do array, ao usar um if dentro dele, e retornando o item atual caso não entre no nele, ex:
const people = [
{ name: 'John Doe', age: 20, country: 'USA' },
{ name: 'Jane Doe', age: 22, country: 'USA' },
{ name: 'Fulano de Tal', age: 18, country: 'Brazil' }
];
const updated = people.map(person => {
if (person.name === 'Jane Doe') {
return {
...person, // copia os dados atuais dela
age: 17 // declare de novo as propriedades que vão ser atualizadas
};
}
return person;
});
Isso é mais útil do que se pode imaginar quando você tem que lidar com situações onde tem que programar usando imutabilidade, como no React por exemplo.
Essa é uma operação bem útil, então podemos até ter uma função utilitária que faz ela para nós:
function updateBy(array, predicate, update) {
return array.map(item => predicate(item) ? update(item) : item);
}
Ela poderia ser escrita sem o parâmetro predicate, mas ai não poderíamos escrever um critério customizado para dizer se o item deve ser atualizado ou não.
# 04 - Rodar promises em paralelo
Promises representam computações assíncronas, e a maior vantagem delas é que você pode rodar todas ao mesmo tempo ao invés de uma atrás da outra, e assim ganhar performance quando isso é possível.
Por exemplo, é muito comum que APIs que implementam o estilo HATEOAS devolvam apenas os ids, talvez algumas informações básicas, e links de navegação ao acessarmos endpoints de listagem ao invés de uma lista completa dos dados, então para listar todos os dados completos é necessário fazer uma requisição para esse endpoint, e depois fazer uma requisição para cada item e só então podemos montar a lista toda, ex:
const list = await fetchList();
const completeList = [];
for (const item of list) {
completeList.push(await fetchItemById(item.id));
}
Um padrão que vimos no post sobre métodos de iteração, com um adicional que todas as requisições vão rodar em serial ao invés de rodarem ao mesmo tempo, para fazer elas rodarem ao mesmo tempo, podemos usar o map em conjunto com o Promise.all
, ex:
const list = await fetchList();
const completeList = await Promise.all(list.map(({ id }) => fetchItemById(id)));
# 05 - Chamar a mesma função várias vezes com parâmetros diferentes
Apesar disso parecer óbvio quando entendemos que o map recebe uma função e produz um novo array com base nela, entretando como a gente foca muito nos dados, essa possibilidade simples pode acabar passando batida.
Uma coisa comum quando estamos desenvolvendo é chamar a mesma função várias vezes seguidas apenas trocando os seus parâmetros, o que leva a um certo grau de duplicação de código, por exemplo, ao usar repetidas vezes o document.querySelector
:
const form = document.querySelector("form");
const input = document.querySelector("input");
const error = document.querySelector("span");
// lógica para validar o formulário e mostrar os erros
Nesse caso, podemos notar que o document.querySelector
foi repetido para cada elemento sendo selecionado, e teria que ser novamente caso precisassemos de mais itens, uma forma de eliminar essa duplicação poderia ser utilizando o map, ex:
const [form, input, error] = ['form', 'input', 'span'].map(selector => {
return document.querySelector(selector);
})
Aqui convertemos cada parâmetro utilizado nas chamadas individuais em um array, ai é só utilizar o map para aplicar a função em cada parâmetro que voila, temos o mesmo resultado só que sem a repetição no nosso código, seguindo bem o princípio DRY.
Conclusão
Espero que tenha gostado do artigo de hoje, não se esqueça de compartilhar com outras pessoas que ainda não descobriram as maravilhas do map caso tenha gostado, e até a próxima.
ASS: O Suporte Cansado
Top comments (0)