JSON: How to create an undefined or NaN value?

Developers Kindergarten

Update 2020-OCT-28

Chrome Version 86. JSON is not a toy.

Here is the story.

There are two flight control systems, on two ends of the globe. Globe has no ends. They communicate in almost real-time by means of messaging. The protocol is agreed. And, JSON is naturally chosen as the message format.

// The protocol
{
  "flight" : "string: flight_number",
  "ETA" : "string: Estimated Time of Arrival"
}

Important and very real detail: both systems core parts are old. Or should we say: ancient. No names, let us proceed.

There are clever parts on both sides, and both sending and receiving JSON formated messages. It is very likely they are both written on NODE.JS. How that actually works?

Sender somehow gets the flight descriptor from its core database, puts it into JSON string and "fire and forget" messaging system takes over. Good. The receiver is also NODE.JS component and it gets that JSON message and passes it to the core on the receiving end. Everyone on the landing airport sees that information on the info boards.

We will skillfully cut through many technology layers here, and postulate the sender using JSON.stringify() and receiver using JSON.parse(), which actually is a simplification but very true. Let the code speak:

// The sender got this data from its core and creates legal javascript object
// rezult goes across the globe to the receiving flight control system
JSON.stringify({"flight": "ABC123", "ETA" : "2020-11-01 23:45:13 GMT"})

After a few seconds, the receiver situation is this:

// JSON formated string has arrived from far away
// it will be transformed first into javascript for further processing
JSON.parse({"flight": "ABC123", "ETA" : "2020-11-01 23:45:13 GMT"})

Now we can abstract this unnecessarily long introduction into this one-liner:

// sender receiver in one line
JSON.parse(JSON.stringify({"flight": "ABC123", "ETA" : "2020-11-01 23:45:13 GMT"}));

Is that safe?

What happens if sender gets the (perfectly legal in the context of data) empty field from its legacy core? For example, "Unimaginable but true"(tm), ETA calculation inside the legacy core, might produce something that will be deciphered as NaN, in the javascript domain. In our condensed notation this is what will happen:

// hickup? core database sends soemthing that javascript deciphers as NaN 
// and yes then sends it acros the globe
JSON.parse( JSON.stringify{"flight": "ABC123", "ETA" : NaN }) )

On the receiving side, the resulting javascript object is now this:

{flight: "ABC123", ETA: null}
// JSON string that has arrived is: 
// "{"flight":"ABC123","ETA":null}"
// JSON.parse thus produced
{flight: "ABC123", ETA: null}
ETA: null
flight: "ABC123"
__proto__: Object

The latest V8 javascript JSON engine parses NaN into null. Why? Is that in some spec somewhere? I do not know. NaN is not null. NaN is a javascript symbol for Not a Number. Very different meaning than null.

That is quickly noticed,. All hands to the battle stations and the following morning NaN is not in use any more. But alas. Our old friend undefined pops back onto the stage!

// one liner from sender to the receiver 
// no NaN, but undefined is used
JSON.parse ( JSON.stringify({"flight": "ABC123", "ETA" : undefined}) )

// receiver got this: '{"flight": "ABC123" }'
{flight: "ABC123"}

No "ETA" property whatsoever. That is one mystery flight indeed. Now, some of you might think I am over-dramatizing the imagined events. I beg to differ. Many of you have experienced the similar barrage of supercritical errors suddenly but sporadically appearing inside some supercritical systems. And then what happens, is the barrage of provoked drastic measures to rectify errors, but them are provoking, in turn, more errors.

In reality, it took approx 72 hours for two distant multidisciplinary and large teams (in very distant time zones) to understand the issue with JSON.stringify and JSON.parse and agree on the obvious solution: Empty field coming from the core system is normal RDBMS situation.

Solutions is to code the empty field "emptiness" into agreed and legal javascript/JSON type. It is normal for database field to be empty. There is no "empty" in JSON design. That "empty" somehow translated into NaN or undefined. No undefines or NaN's can be simply put into JSON and just "carried over". Code had to be added which translated empty database fields into javascript null. Yes, they have finally agreed the protocol change, if "ETA" field is null that means "empty".

Although they are arguing to this day would it be better to use an empty string instead of null?

Update 2020-FEB-07

// parsing strings into JSON
// returns:{"a" : null }
JSON.parse('{ "a" : null }'); 
// throws
// VM3352:1 Uncaught SyntaxError: Unexpected token u in JSON at position 8
JSON.parse('{ "a" : undefined }'); 
// throws
// Uncaught SyntaxError: Unexpected token N in JSON at position 8
JSON.parse('{ "a" : NaN }');

Thus two legal Java Script symbols (undefined and NaN) can not be made part of JSON formatted string. That is just the first peculiarity.

// three JavaScript strings 
'{ "a" : null }'
'{ "a" : undefined }'
'{ "a" : NaN }'

Even more troubling fact is: that kind of “naughty JSON” text can be sent over a wire between two distant systems. And you can be on the receiving side. Can they be used as JSON in the javascript code?

// Chrome 80, F12 Console
// returns {"a" : NaN}
{"a" : NaN}
// returns {"a" : undefined }
{"a" : undefined }

Well, this is confusing. And I am not sure how I would solve this dichotomy as part of JSON spec? Is this already solved, I do not know? So, was it much worse 7 years ago? Hint: no, it was not.

Update 2013-SEP-11

Or is the result of 1/0 ‘Infinity’ as this science called mathematics tells us? In any case and at this moment in time, and looking into this JSON conundrum, I started to think I had no idea.

first published 2013JAN01

Consider for example this little “number” :

  document.writeln(
   JSON.stringify(
     {
      a: 2,
      b: undefined
     })
  );

That produces

{ "a" : 2 }

Property “b” is simply and quietly not created, or so it seems? Perhaps it is me who is wrong or I need to go back to ES5 specification?

JSON NOT to the rescue

The problem is not in some esoteric ES5 “feature” (aka omission) but it is an “issue” with JSON. JSON was created to ignore undefined (and functions, NaN’s, and Infinity-es). And yes I knew this. I started this post in this way because I also wanted to show how this kind of “feature” can catch anybody off-guard. And repeatedly at that.

Never use JSON.stringify() for debugging

Object literal above is not a mistake. It really produces an object with properties “a” and “b”, where “b” is indeed undefined. And crucially key “b” does exist, and its value is undefined. So, back to senses, hit F12 in your venerable Chrome or IE, and try this:

console.dir(
   {
    a: 2,
    b: undefined
   })

And voila, the output is the actual object created, with two properties present:

Object
a: 2
b: undefined
__proto__: Object

Not out of this wood, yet

This might be one happy ending to one blog post, but alas it is not. Far from that. The big worm in that big can is this: How is this reflected on AJAX? How are XMLHTTPREQUEST implementations out there handling this JSON “feature”?

Namely: how is one passing a JSON object where some keys might have values as e.g. undefined? JSON encoded object like this one:

'{ "a" : 2, "b" : undefined }'

is of course NOT a good JSON and resident JSON.parse() method on the receiving side will throw a syntax error:

SyntaxError: Unexpected token u
/*
2014 SEP 11 Update :
In IE11 Console for some reason this is "Invalid character", Error ?
*/

I am not even sure I can hope that the sending side will allow me to come to the above. That is I am not sure how to pack the offending object into the valid JSON string.

Valid requirement. Although 1/0 is 'Infinity'.

wrong wiki

1/0 is ‘Infinity’. It is not ‘undefined’. This Wikipedia image is wrong.

So, what gives? I see no other way but to perhaps use ‘null’ instead of undefined’? But then I have no simple/native/natural way of JSON trustingly encoding the object which (for example) represents the calculation of the table from the image in this post ).

if x is zero then 1/x is not ‘null’. It is mathematically represented as ‘infinity’, not as ‘null’. And not as “undefined” either, as a table on the image is wrong. Strictly 1/0 is Infinity, but then JSON encoding rules do not allow that too: Infinity is not a legal value in JSON.

// IE11 (2014SEP11) produces this kind of delicious
// desert for ECMA deep divers to enjoy
undefined == null      // => true
undefined === null   // => false

Undefined “is” null but its identity is not null … We are definitely not in the “good parts” of JavaScript, a territory in here.

In pure JavaScript, I can compute NaN or Infinity values or hold undefined ones, but how do I express in JSON that something is undefined, Infinity or NaN? Beside putting it in a string: “undefined”, “NaN”, “Infinity”.

NaN, undefined, and null are three distinctive values. And just like any other values in JavaScript

// ECMA 
NaN + "" // =>  string 'NaN'
undefined + "" // => string 'undefined'
null + "" // => string 'null'

Solution? Direction? Perhaps, but solution no. If I have to “decode” these strings into values on the receiving side, this introduces yet another level of encoding of “special” values and that is not a good thing. Not at all.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 thoughts on “JSON: How to create an undefined or NaN value?”