The Legend of Dave
The Legend of Dave

Reputation: 304

Can I make a JSON-stringified object have a field whose value is a double in Javascript?

I am POSTing JSON from my Javascript application to this API that behaves differently if you send it doubles vs. ints. I just use JSON.stringify to build my request bodies. I always want to send doubles. But when I have Javascript numbers that are integral, JSON.stringify does this:

> JSON.stringify({x: 1.0});
'{"x":1}'

That unadorned 1 goes to the API where the other server thinks it's an int, and I get the integer behavior, which I don't want. Is there any known hack to get a double in my JSON in Javascript?

Upvotes: 0

Views: 393

Answers (3)

Nick
Nick

Reputation: 11

Another approach: build a custom version of JSON.stringify which will always output numbers with a decimal point.

This simply takes an example implementation from the Mozilla JSON documentation and modifies the line of code that handles numbers:

window.JSON.stringifyDecimal = (function(){
  var toString = Object.prototype.toString;
  var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
  var escMap = {'"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t'};
  var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
  var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;
  return function stringify(value) {
    if (value == null) {
      return 'null';
    } else if (typeof value === 'number') {

      // Ensure decimal point is present
      return isFinite(value) ? value.toString() + ( Number.isInteger( value ) ? '.0' : '' ) : 'null';

    } else if (typeof value === 'boolean') {
      return value.toString();
    } else if (typeof value === 'object') {
      if (typeof value.toJSON === 'function') {
        return stringify(value.toJSON());
      } else if (isArray(value)) {
        var res = '[';
        for (var i = 0; i < value.length; i++)
          res += (i ? ', ' : '') + stringify(value[i]);
        return res + ']';
      } else if (toString.call(value) === '[object Object]') {
        var tmp = [];
        for (var k in value) {
          if (value.hasOwnProperty(k))
            tmp.push(stringify(k) + ': ' + stringify(value[k]));
        }
        return '{' + tmp.join(', ') + '}';
      }
    }
    return '"' + value.toString().replace(escRE, escFunc) + '"';
  };
})();

Upvotes: 1

Racil Hilan
Racil Hilan

Reputation: 25351

With JSON, you have two parties: The writer and the reader. In your case, the writer is your request and you're using JSON.stringify to generate the JSON string, and the reader is the API (which I don't know what it uses to parse the string back to a JSON object). You need both sides to be able to understand that 1.0 should stay as is because it's a double not an integer.

JSON string itself is just text and keeps whatever you give it as is. It is the JSON.stringify that is converting 1.0 to 1, so you can easily create your JSON string manually instead of using JSON.stringify:

var text = JSON.stringify({x: 1.0}); //JSON string will be {"x": 1}
var text = '{"x": 1.0}'; //JSON string will be exactly {"x": 1.0}

However, even if you do that, you need the other side (i.e. the API) to parse the value 1.0 as double, not an integer. Is that under your control? For example, the JavaScript JSON.parse function will parse the 1.0 as 1 exactly like JSON.stringify does:

var obj = JSON.parse('{"x": 1.0}');
alert(obj.x); //It prints 1, even though we gave it 1.0

Upvotes: 0

melpomene
melpomene

Reputation: 85827

JSON (and JavaScript in general) don't distinguish between different numeric types; there's only "number". As such this is a bit outside the scope of JSON.stringify.

Here's a pretty awful workaround:

JSON.stringify({x: 1.0}).replace(
    /("(?:[^"\\]|\\.)*")|[\[:,]\s*-?\d+(?![\d.eE])/g,
    function (m0, m1) { return m1 || m0 + '.0'; }
)

This (rather big hammer) uses a regex to add .0 to all numbers that don't already have a . and are not part of a quoted string.

Upvotes: 1

Related Questions