14

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.

6
  • 5
    JSON contains only strings. If a value is undefined it would also have to be converted to a string. What happens if I'm going to transfer a string which has the same value as the string-representation of undefined? How to distinguish which "undefined" is which. But if you really want to go this way then you can pass a replacer function as the second parameter of JSON.stringify(value[, replacer[, space]]) -> developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Jul 8, 2015 at 5:38
  • Like I said in the question, I understand the mechanics of what is going on - but I am unsatisfied as to why it does it. The function you link to is obviously a solution, but is not something that I believe should be required for this in the first place :) Also as a side note, JSON contains other data types, not only strings (bools, arrays) Commented Jul 8, 2015 at 5:39
  • You're right for bools and numbers. But arrays are also translated into their string representation. undefined is not a defined value for JSON. If you really need to change the defined behaviour of JSON then you will have to use a replacer function. Commented Jul 8, 2015 at 5:47
  • Ah ok. I don't want to change the behaviour of JSON, I want to change the JSON.stringify method accordingly to reflect JSON's limitations. To clarify - I know how to do to this, what I'm saying is this should be default behaviour. Commented Jul 8, 2015 at 5:49
  • 3
    Seems to me this is actually a question for a JSON discussion group and has nothing to do with JavaScript (other than the J in JSON). Perhaps remove the javascript tag? Commented Jul 8, 2015 at 5:53

2 Answers 2

11

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

Sign up to request clarification or add additional context in comments.

Comments

6

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}'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.