Olá Gabriel, tudo bem?
Se entendi bem, você quer saber por que a função aplicarDesconto()
está alterando os valores nos objetos do próprio array livros
e não retornando um array com os valores alterados (aplicados o desconto) sem alterar o original, correto?
Bom, na verdade AMBAS as coisas estão acontecendo. Explico!
Vamos analisar esse trecho do seu código:
return livros.map((livro) => livro.preco = Math.round(livro.preco * (1 - desconto)));
Prestando bastante atenção aos comandos utilizados, vemos que a função callback usada no método .map()
está calculando o desconto para cada livro e aplicando esse desconto à propriedade preco
do objeto livro
que está sendo analisado à cada chamada. Objetos em JavaScript são do tipo "referência", ou seja, quando o método .map()
percorre cada um dos itens do array livros
NÃO estamos tendo acesso a uma "cópia" desses objetos, mas sim, ao objeto em si por meio de sua referência em memória. Sendo assim, ao realizarmos qualquer modificação neste objeto, o estamos alterando diretamente e se estamos alterando o objeto "original" e ele está dentro de um array (no caso "livros") então estamos alterando de alguma forma o conteúdo desse array.
Então, quando executamos a atribuição livro.preco = Math.round(livro.preco * (1 - desconto))
estamos alterando cada um dos objetos livro
presentes no array livros
através de sua referência em memória e assim, alterando o conteúdo do próprio array e, de quebra, o método .map()
ainda está retornando um array que contém apenas os preços dos livros existentes no array livros
aplicados os descontos.
Para não alterarmos o conteúdo do array principal (o array livros
) basta não atribuirmos o resultado do cálculo do desconto à propriedade preco
de cada livro
conforme o código abaixo:
// retorna um array apenas com os preços de cada livro aplicados o desconto, ex: [129.30, 79.90, 52.67]
// sem atribuí-los aos objetos "livro" analisados
return livros.map((livro) => Math.round(livro.preco * (1 - desconto)));
Isso já resolveria o "problema" da modificação no array original.
Agora, se quisermos retornar um array totalmente novo com TODOS os objetos livro
tendo seu preço atualizado com os descontos aplicados SEM ALTERAR o array original, teríamos que fazer uma cópia de cada objeto livro
com o desconto aplicado ao preço (a cópia se faz necessária para que a mesma referência em memória não seja compartilhada entre eles, isto é, que o objeto DE FATO seja completamente novo contendo as mesmas informações do objeto livro
que o originou). Isso pode ser alcançado com o código de exemplo abaixo:
// retorna um array com cópias de todos os objetos livro existentes no array livros
// porém com o desconto aplicado ao preço de cada um deles
return livros.map((livro) => {
return {
...livro,
preco: Math.round(livro.preco * (1 - desconto))
};
});
Perceba que a função callback do método .map()
retorna agora não o valor do preço aplicado o desconto somente, mas sim, um objeto completamente novo que contém a cópia das propriedades e valores de cada livro
percorrido pelo método .map()
:
return {
...livro
}
Veja que usamos um operador chamado Spread Operator (...
) para "espalhar" todos os valores e propriedades do objeto livro
no novo objeto anônimo que estamos criando para representar esse livro ({ }
).
Contudo, precisamos alterar a propriedade preco
para que ela tenha o valor atualizado (aplicado o desconto) e não o valor original. Sendo assim, sobrescrevemos apenas a propriedade que queremos alterar desse objeto, atribuindo a ela o novo preço:
return {
...livro,
preco: Math.round(livro.preco * (1 - desconto))
};
Assim, o map vai retornar um array que é uma CÓPIA EXATA do array livros
, porém com todos os preços dos livros atualizados e isso sem alterar o array original.
Ufa... bastante coisa, né?!
Bom, espero que tenha ficado claro e que eu tenha conseguido sanar sua dúvida.
Qualquer coisa, estamos por aqui.
Att.