I've not seen (yet?) JSON.stringify
to be non-deterministic in Node.JS.
There is no guarantee it to be deterministic on the specification level.
But what about V8; Is its implementation there deterministic? Is there a guarantee for it to remain deterministic for future V8 versions?
Edit:
With deterministic I mean that following assertion is true no matter what the value of json_str
is. (Given the value is a valid JSON string.)
const obj = JSON.parse(json_str);
assert(JSON.stringify(obj)===JSON.stringify(obj)); // always true
Edit 2:
Actually, I'm also interested for the following assertion to be true
if( deepEqual(obj1, obj2) ) {
assert(JSON.stringify(obj1)===JSON.stringify(obj2))
}
which is not the case (see answers).
To clarify jmrk's answer;
According to the spec, integer keys are serialized in numeric order and non-integer keys in chronological order of property creation, e.g.;
var o = {};
o[2] = 2;
o.a = 3;
o.b = 4;
o["1"] = 1;
assert(JSON.stringify(o)==='{"1":1,"2":2,"a":3,"b":4}');
Therefore following assertion is guaranteed to be true
if( obj1 === obj2 ) {
assert(JSON.stringify(obj1) === JSON.stringify(obj2));
}
but two "deep equal" objects may be serialized into different strings;
var obj1 = {};
obj1["a"] = true;
obj1["b"] = true;
assert(JSON.stringify(obj1)==='{"a":true,"b":true}');
var obj2 = {};
obj2["b"] = true;
obj2["a"] = true;
assert(JSON.stringify(obj2)==='{"b":true,"a":true}');
Spec quote;
- Let keys be a new empty List.
For each own property key P of O that is an integer index, in ascending numeric index order, do
a. Add P as the last element of keys.
For each own property key P of O that is a String but is not an integer index, in ascending chronological order of property creation, do
a. Add P as the last element of keys.
For each own property key P of O that is a Symbol, in ascending chronological order of property creation, do
a. Add P as the last element of keys.
- Return keys.
From https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys
If by "deterministic" you mean enumeration order of the object's properties: that is actually specified, and V8 follows the spec. See https://tc39.github.io/ecma262/#sec-ordinaryownpropertykeys. [Edit: this is the answer to your clarified definition, so yes, JSON.stringify is deterministic in that sense.]
If by "deterministic" you mean "always returns the same string for the same input object", then, well, no :-)
> var o = { toJSON: function() { return Math.random(); } }
> JSON.stringify(o);
< "0.37377773963616434"
> JSON.stringify(o);
< "0.8877065604993732"
Proxy
objects and the replacer
argument to JSON.stringify
can also be used to create arbitrary behavior (even though JSON.stringify
itself always does the same thing).
If by "deterministic" you mean something else, please specify.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With