Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does JSON.stringify ignore keys whose values are undefined?

To be more accurate, I understand why this technically happens - since undefined is not a valid JSON type:

var breakfast = {
    "cereal" : "fruit loops",
    "pastry" : undefined
};

console.log(breakfast);
// -> { cereal: 'fruit loops', pastry: undefined }

console.log(JSON.stringify(breakfast));
// -> {"cereal":"fruit loops"}

My question is - why is this considered acceptable behaviour? There are clearly valid reasons why I would want to pass undefined as part of an API or whatever. This seems somewhat dangerous - why wouldn't the function raise an error instead of brazenly taking it upon itself to change my data without warning? This seems like a bit of a running thread with JS.

like image 967
Mark Avatar asked Jul 08 '15 05:07

Mark


People also ask

Does JSON Stringify remove undefined?

JSON. stringify will omit all object attributes that are undefined .

Does JSON allow undefined values?

Undefined is not a valid JSON type. All javascript objects are not valid JSON and vice versa. All other values will be sent to the response but undefined won't be sent.

What Cannot be JSON Stringify?

undefined , Function , and Symbol values are not valid JSON values. If any such values are encountered during conversion, they are either omitted (when found in an object) or changed to null (when found in an array).


2 Answers

The answer to this lies in the ECMA-262 spec. In section 24.3.2 JSON.stringify ( value [ , replacer [ , space ] ] ), the spec clearly states that:

NOTE 2

The undefined value is not rendered.

Further:

NOTE 5

Values that do not have a JSON representation (such as undefined and functions) do not produce a String. Instead they produce the undefined value. In arrays these values are represented as the String null. In objects an unrepresentable value causes the property to be excluded from stringification.

Thus, JSON.stringify() as you are using it is perfectly following the existing ECMA spec.

Even using a replacer, without specifically specifying your own function, the default replacer rules state that items should only be appended:

24.3.2 Subsection 4.b.5.g

If item is not undefined and item is not currently an element of PropertyList

like image 64
Matthew Herbst Avatar answered Oct 06 '22 00:10

Matthew Herbst


JSON is meant to be language agnostic. It already supports null. Supporting undefined as well would impose the handling of one of JavaScript's idiosyncrasies on other languages, which defeats the purpose of easy interoperability.

'JSON's design goals were for it to be minimal, portable, textual, and a subset of JavaScript.'

As for not throwing an error, well

var x = { foo: undefined };
x.foo === undefined; // true
var json = JSON.stringify(x);
var y = JSON.parse(json);
y.foo === undefined; // true

So JSON.stringify can create a string that represents the value x. Throwing an error would not be useful in this case. In fact JSON.stringify ignores all values that don't have a JSON representation, so functions are ignored to. This makes it easy to serialise object data, for example.

Finally, bear in mind that JSON.stringify takes a replacer function as an argument which can be used to alter the way stringification takes place. So to make JSON.stringify throw existing properties with an undefined value:

var replacer = function(key, value){
    if(value === undefined){
        throw 'JSON.stringify: bad property: ' + key;
    }
    return value;
};

var x = {foo: undefined};
JSON.stringify(x, replacer);
// uncaught exception: JSON.stringify: bad property: foo

Or to replace with null:

var replacer = function(key, value){
    if(value === undefined){
        return null;
    }
    return value;
};

var x = {foo: undefined};
JSON.stringify(x, replacer); // '{"foo":null}'
like image 34
1983 Avatar answered Oct 06 '22 00:10

1983