É possível impedir que um dos atributos de um objeto seja serializado em Javascript? – javascript json

Pergunta:


Há alguma maneira de impedir que um dos atributos de um objeto seja serializado?

Tome como exemplo o objeto abaixo. Se eu não quiser que propriedade2 seja serializado, como eu poderia implementar isso?

var obj = {
  propriedade1 : 'teste 1',
  propriedade2 : {
    subpropriedade1 : 'teste 2 - 1',
    subpropriedade2 : 'teste 2 - 2'
  },
  propriedade3 : 'teste 3',
  propriedade4 : {
    propriedade1 : 'teste 4 - 1'
  }
}

var obj2 = new Object();
obj2.propriedade1 = 'teste 1';
var prop2 = new Object();
prop2.subpropriedade1 = 'teste 2 - 1';
prop2.subpropriedade2 = 'teste 2 - 2';
obj2.propriedade2 = prop2;
obj2.propriedade3 = 'teste 3';
var prop4 = new Object();
prop4.propriedade1 = 'teste 4 - 1';
obj2.propriedade4 = prop4;

console.log(JSON.stringify(obj));
console.log(JSON.stringify(obj2));
Autor da pergunta Artur o Templário

bfavaretto

Uma outra maneira é criar uma propriedade não enumerável. Propriedades não enumeráveis não são acessadas em laços for..in, nem são incluídas na geração de JSON.

Exemplo:

var o = {};
Object.defineProperty(o, 'teste', { enumerable: false, writable: true });
o.teste = 10;
console.log(o.teste);          // 10
console.log(JSON.stringify(o)) // "{}"

Ainda não consigo comentar, então apenas acrescentando a resposta do @AndersonCarlosWoss. Uma terceira opção, é o próprio objeto decidir quais propriedades ele deseja serializar:

var obj = {
  prop1: "String",
  prop2: 1,
  prop3: true,
  toJSON: function(){
    return {
      prop1: this.prop1,
      prop2: this.prop2
    };
  }
};

console.log(JSON.stringify(obj));

Para simplificar o entendimento, criarei um exemplo mais próximo da realidade:

const obj = {
    "name": "John Doe",
    "age": 34,
    "parents": [
        {
            "name": "Derp",
            "age": 63,
            "gender": "male"
        }, {
            "name": "Derpina",
            "age": 62,
            "gender": "female"
        }
    ]
};

Supondo que a intenção é serializar o objeto obj ignorando o atributo age. Um detalhe é que não somente o próprio objeto possui o atributo age, como também objetos filhos possuem (nesse caso, os dois objetos em parents). Se a intenção, nesse caso, é de remover todos os atributos age, não importando onde esteja, há duas soluções (outras foram abordadas nas outras respostas):

Primeira solução: passar como segundo parâmetro de JSON.stringify uma lista dos atributos que deseja manter ao serializar o objeto. Porém, essa lista de atributos não deve abordar apenas os atributos do objeto original, mas todos os atributos de todos os objetos relacionados que é desejado manter. Por exemplo, os objetos internos a parents possuem o atributo gender que o objeto principal não possui e mesmo assim tal atributo deve ser listado:

const obj = {
    "name": "John Doe",
    "age": 34,
    "parents": [
        {
            "name": "Derp",
            "age": 63,
            "gender": "male"
        }, {
            "name": "Derpina",
            "age": 62,
            "gender": "female"
        }
    ]
};

console.log(JSON.stringify(obj, ["name", "parents", "gender"]));

Se gender não for listado, o atributo será removido dos objetos internos ao efetuar a serialização.

Segunda solução: também utilizando o segundo parâmetro de JSON.stringify, mas agora definindo uma função que executará a lógica de manter ou não um valor no objeto. A função recebe dois parâmetros: a chave, nome do atributo, e seu respectivo valor. A lógica aqui seria bem simples: se a chave condizer com o atributo que desejamos remover, retornamos o valor undefined, caso contrário, retorna o próprio valor.

const obj = {
    "name": "John Doe",
    "age": 34,
    "parents": [
        {
            "name": "Derp",
            "age": 63,
            "gender": "male"
        }, {
            "name": "Derpina",
            "age": 62,
            "gender": "female"
        }
    ]
};

console.log(JSON.stringify(obj, function (key, value) {
    if (key == "age") {
        return undefined;
    }
    
    return value;
}));

Esta forma é relativamente mais versátil que a primeira, pois ao invés de especificar quais atributos você deseja manter, você especifica quais atributos deseja remover, não importando a estrutura do restante do objeto.

Não modificando objetos internos

Ambas as soluções removem o atributo dos objetos mais internos, então, se a intenção é de mantê-los, removendo o atributo do objeto principal, outras soluções são necessárias.

Função toJSON: como apresentado na resposta do L.Albano, é possível definir uma função toJSON no objeto que será chamada ao serializar o mesmo. O resultado da serialização será, na verdade, a serialização do retorno desta função. L. Albano mostrou como fazer o clone do objeto manualmente, mas é possível fazer de forma dinâmica e, depois, remover o atributo desejado.

const obj = {
    "name": "John Doe",
    "age": 34,
    "parents": [
        {
            "name": "Derp",
            "age": 63,
            "gender": "male"
        }, {
            "name": "Derpina",
            "age": 62,
            "gender": "female"
        }
    ],
    toJSON: function () {
        
        // Clona o objeto:
        const clone = Object.assign({}, this);
        
        // Remove o atributo desejado:
        delete clone["age"];
        
        // Retorna o clone modificado:
        return clone;
    }
};

console.log(JSON.stringify(obj));

Desta forma, apenas o atributo age do objeto principal é removido, enquanto dos objetos internos são mantidos.

Clonar o objeto utilizando Object.assign só é possível a partir do ECMAScript 5 (ES6), porém, se desejável, existem polyfills. Outra técnica de clonar objetos é combinar JSON.parse com JSON.stringify, porém esta técnica não é aplicável neste exemplo pois geraria uma recursão infinita.

Fonte

Related Posts:

Qual a diferença entre AppCompatActivity e Activity? – android android-activity
Pergunta: Qual a diferença da AppCompatActivity para Activity ? A partir de qual versão a AppCompatActivity foi adicionada ao Android? Autor da pergunta Luhhh A diferença reside ...
Como abreviar palavras em PHP? – php string
Pergunta: Possuo informações comuns como nome de pessoas e endereços, e preciso que elas contenham no máximo 30 caracteres sem cortar palavras. Exemplo: 'Avenida Natalino João Brescansin' ...
Qual é a finalidade de um parêntese vazio numa declaração Lambda? – c# expressões-lambda característica-linguagem
Pergunta: Criei um exemplo de uma declaração Lambda sem argumentos, entretanto, estou com duvidas referente a omissão do parêntese vazio () na declaração. Veja o exemplo: class ...
Boas práticas para URI em API RESTful – api rest restful
Pergunta: Estou com dúvida em relação às URIs de alguns recursos da api que estou desenvolvendo. Tenho os recursos projetos e atividades com relação 1-N, ...
Dúvidas sobre a integração do MySQL com Java – java mysql netbeans
Pergunta: Estou criando um sistema no NetBeans, utilizando a linguagem Java e o banco de dados MySQL. Escrevi o seguinte código para realizar a conexão ...
Qual é a finalidade da pasta Model do framework Inphinit? – php inphinit
Pergunta: No Inphinit micro-framework existe a pasta Model que fica dentro da pasta application, e nela é onde ficam as classes, mas eu estou muito ...
Uso do ‘@’ em variáveis – javascript typescript coffeescript
Pergunta: Vejo em algumas linguagens que compilam para javascript, como TypeScript e CoffeeScript, o uso do @ em variáveis, como também, casos em que o ...
Qual tamanho máximo um arquivo JSON pode ter? – json arquivo
Pergunta: Vou dar um exemplo para conseguir explicar minha duvida: Preciso recuperar informação de imagens vindas de uma API, esse banco de imagens me retorna JSON's ...
O que é Teste de Regressão? – terminologia engenharia-de-software testes
Pergunta: Na matéria de Teste de Software o professor abordou um termo chamado Teste de Regressão, isto dentro da disciplina de teste de software. Sendo ...
O que é um construtor da linguagem? – php característica-linguagem
Pergunta: Em PHP, já li e ouvi várias vezes a respeito dos Construtores da Linguagem. Os casos que sempre ouvi falar deles foi em casos ...
Função intrínseca para converter numérico para string – cobol
Pergunta: Estou a tentar saber se existe alguma função intrínseca do COBOL para converter um data numérico para string sem precisar usar a cláusula REDEFINES: ( ...
Porque usar implements? – java android
Pergunta: Qual a diferença entre usar btn.setOnClickListener(new OnClickListener() { e public class MainActivity extends Activity implements OnClickListener{ Estive fazendo um curso de Android e meu professor falou que ...
O que é XHTML e quando deve ser usado? – html xml xhtml
Pergunta: O que eu sei é que o XHTML precisa ser XML válido. Isso implica, por exemplo, que todas as tags precisam ser fechadas. Por ...
Uma placa aceleradora de vídeo pode melhorar o desempenho não-gráfico? [fechada] – desempenho
Pergunta: Para desenvolver em Ruby on Rails, eu utilizo aqui uma máquina virtual do VirtualBox com Ubuntu Server 14.04 sem interface gráfica instalada. Recentemente descobri uma ...
Concat() VS Union() – c# .net
Pergunta: Qual a diferença entre Concat() e Union() ? Quando usar Concat() e quando usar Union() ? Somente pode ser usado em list ? ...

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *