Evitando a serialização de propriedades dinâmicas de objetos
O problema
Existem várias maneiras de adicionarmos flags de controle em objetos JavaScript. Uma delas é modificando o objeto diretamente:
// dados que podem vir de uma API web
const photo = {
title: 'Cangaceiro JavaScript',
author: 'Flávio Almeida'
}
// propriedade de controle que define um identificador único
photo._key = 1;
Todavia, ao serializarmos o dado para ser enviado para uma API, a propriedade _key
estará presente:
const serializedPhoto = JSON.stringify(photo);
console.log(serializedPhoto);
/*
{
title: 'Cangaceiro JavaScript',
author: 'Flávio Almeida',
_key: 1
}
*/
Isso não seria um problema caso a API seguisse a boa prática de pinçar (pluck) apenas as propriedades que espera receber. Mas caso a API não siga esse caminho, fica evidente que não podemos enviar a propriedade _key
.
Serializar o JSON em disco na plataforma Node.js também seria um problema, pois a propriedade também faria parte do dado serializado.
Uma solução é apagarmos a propriedade adicionada dinamicamente antes da serialização:
// código anterior omitido
delete photo._key; // apagando a propriedade
const serializedPhoto = JSON.stringify(photo);
delete serializedPhoto._key;
console.log(serializedPhoto);
A motivação para o post veio do problema enfrentado por um colega em sua aplicação feita com Ionic 3. Uma das bibliotecas utilizadas por ele modificava diretamente o modelo associado ao componente o que acabava lhe causando problemas na arquitetura definida por ele.
O exemplo acima não causaria grandes problemas de performance, mas o cenário seria diferente caso tivéssemos que iterar em um grande lista de objetos para então deletarmos a propriedade _key
de cada um deles. A boa notícia é que há outra solução.
Definindo propriedades não iteráveis
Uma solução para o problema anterior é adicionarmos no objeto a propriedade _key
como não enumerável. Uma propriedade não enumerável não será enxergada por repetições for...in
ou pelo método Object.keys()
. Como a função JSON.stringify()
utiliza alguma estrutura de iteração para construir o JSON resultante, propriedades não enumeráveis serão ignoradas.
Um pouco sobre Object.defineProperty
Criamos propriedades não iteráveis com auxílio da função Object.defineProperty
. Ela recebe como primeiro parâmetro o objeto que desejamos modificar e como segundo o nome da propriedade que será adicionada. Por fim, um objeto descritor (descriptor) é passado como último parâmetro. É nele que indicamos que a propriedade é não enumerável através de enumerable: false
, inclusive seu valor através de value: 1
:
Modificando nosso código:
const photo = {
title: 'Cangaceiro JavaScript',
author: 'Flávio Almeida'
}
Object.defineProperty(photo, '_key', {
enumerable: false,
value: 1
});
const serializedPhoto = JSON.stringify(photo);
console.log(serializedPhoto);
/*
{
title: 'Cangaceiro JavaScript',
author: 'Flávio Almeida',
}
*/
O JSON resultante não contém mais a propriedade _key
, excelente.
Conclusão
Podemos adicionar dinamicamente em objetoa propriedades não enumeráveis através de Object.defineProperty
. Uma consequência dessas propriedades é que elas não farão parte do JSON criado através da função JSON.stringify
.
A função Object.defineProperty
permite definir ainda outras características da propriedade adicionada dinamicamente. E você? Já precisou utilizar essa função antes? Qual problema você tentou resolver? Deixe sua opinião.