Can you prevent one of the attributes of an object from being serialized in Javascript?

13

Is there any way to prevent one of the attributes of an object from being serialized?

Take the following example as an example. If I do not want propriedade2 to be serialized, how could I implement this?

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));
    
asked by anonymous 29.09.2017 / 21:31

3 answers

11

Another way is to create a non-enumerable property. Non-enumerable properties are not accessed in for..in loops, nor are they included in JSON generation.

Example:

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

I can not comment yet, so just adding @AndersonCarlosWoss's answer. A third option, the object itself decides which properties it wants to serialize:

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

console.log(JSON.stringify(obj));
    
29.09.2017 / 22:34
8

To simplify understanding, I'll create an example closer to reality:

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

Assuming the intention is to serialize the object obj by ignoring the age attribute. A detail is that not only the object itself has the age attribute, but also child objects have (in this case, the two objects in parents ). If the intention in this case is to remove all age attributes, no matter where it is, there are two solutions (others have been addressed in the other responses):

First solution: pass as second parameter of JSON.stringify a list of the attributes that you want to keep when serializing the object. However, this list of attributes should not only address the attributes of the original object, but all the attributes of all related objects that it is desired to maintain. For example, the internal objects parents have the gender attribute that the main object does not have and even then that attribute must be listed:

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"]));

If gender is not listed, the attribute will be removed from internal objects when serializing.

Second solution: also using the second parameter of JSON.stringify , but now defining a function that will execute the logic of maintaining or not a value in the object. The function receives two parameters: the key, the name of the attribute, and their respective value. The logic here would be quite simple: if the key matches the attribute we want to remove, we return the value undefined , otherwise it returns the value itself.

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;
}));

This form is relatively more versatile than the first, because instead of specifying which attributes you want to keep, you specify which attributes you want to remove, regardless of the structure of the rest of the object.

Not modifying internal objects

Both solutions remove the attribute from the most internal objects, so if you want to keep them by removing the attribute from the main object, other solutions are needed.

toJSON function: as shown in the L.Albano response , it is possible define a toJSON function on the object that will be called when serializing it. The result of serialization will actually be the serialization of the return of this function. L. Albano showed how to do the object clone manually, but it is possible to do it dynamically and then remove the desired attribute.

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));

In this way, only the age attribute of the main object is removed, while the internal objects are retained.

  

Cloning the object using Object.assign is only possible from ECMAScript 5 (ES6), but if desired, there are polyfills . Another technique of cloning objects is to combine JSON.parse with JSON.stringify , however this technique is not applicable in this example since it would generate an infinite recursion.

    
29.09.2017 / 21:48