Preserve property attributes (writable, custom) after JSON.parse ()

Lets say that I am creating an object elsewhere and passing it somehow to my module. Maybe it was created on the server in node.js

, maybe it was created in another module and for some reason I JSON.stringify()

started it and passed the serialized version (especially if it came from the server). But I want this particular property to be immutable:

var foo = {};

Object.defineProperty(foo, 'bar', {
    value: 'bar',
    writeable: false,
    enumerable: true
});

console.log(foo.bar); //bar
foo.bar = 'foo';      //fails, throws err in strict
console.log(foo.bar); //still bar

var fii = JSON.parse(JSON.stringify(foo));

console.log(fii.bar); //still bar
fii.bar = 'foo';      //succeeds      
console.log(fii.bar); //now foo

      

Is there a way to preserve this metadata so that the property is bar

immutable without sending it separately?

+3


source to share


1 answer


You can string together property descriptors as in

// set up object to be serialized--from OP question
var foo = {};
Object.defineProperty(foo, 'bar', {
    value: 'bar',
    writable: false,
    enumerable: true
});

// create an object of property descriptors
var descriptors = {};
Object.keys(foo).forEach(function(key) {
    descriptors[key] = Object.getOwnPropertyDescriptor(foo, key);
});

var json = JSON.stringify(descriptors);
// "{"bar":{"value":"bar","writable":false,"enumerable":true,"configurable":false}}"

      

Now, to restore:

descriptors = JSON.parse(json);
foo = {};
Object.defineProperties(foo, descriptors);

      

Of course, this will not work with accessor type descriptors that contain get

and / or set

nested objects, etc. etc.



Using flags on keys

Another idea is to encode the writeability into the key name through path and path conversions:

// Mark unwritable properties by changing keyname to 'prop:unwritable'.
function markImmutable(obj) {
    for (var p in obj) {
        if (!Object.getOwnPropertyDescriptor(obj, p).writable) {
            obj[p + ':unwritable'] = obj[p];
            delete obj[p];
        }
    }
}
markImmutable(foo)
> Object {bar:unwritable: "bar"}

      

Then tweak that, and after parsing, do the reverse transformation.

0


source







All Articles