25

$.parseJSON("1") returns 1. I would expect this to throw an error because this does not seem like valid JSON of the form:

{
    "firstName": "John"
}

Why does 1 parse correctly? Is there anyway to get this to throw an error instead.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
Alexis
  • 23,545
  • 19
  • 104
  • 143
  • 5
    `Number` is a primitive data type. `JSON` is valid if the value is a primitive data type – Sushanth -- Jun 20 '13 at 21:59
  • @Sushanth--Not according to jslint.com. This is an interesting question – landons Jun 20 '13 at 21:59
  • do you want that in case of "1" is used you throw an error ? – Mehdi Karamosly Jun 20 '13 at 22:01
  • 3
    My guess is it works because it also works for `JSON.parse("1")` – Kevin B Jun 20 '13 at 22:02
  • It also works for any number, not just 1, parseJSON("999") will return 999 – Mostafa Berg Jun 20 '13 at 22:03
  • 2
    Any of the railroad charts on http://www.json.org are valid JSON and should be parsable by a good implementation of `parseJSON`. – FishBasketGordo Jun 20 '13 at 22:11
  • not just `1` every number is valid like this one `$.parseJSON("-50.26e+256");` – Adil Shaikh Jun 20 '13 at 22:12
  • how can I get this to throw an error or check to see if it is just one number? – Alexis Jun 20 '13 at 22:14
  • @Alexis Why not use [`parseInt(string)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) for parsing a number? – Bart Jun 20 '13 at 22:34
  • 1
    @FishBasketGordo That's not true. A JSON parser only has to parse JSON text. JSON text is a serialized object or array. A JSON value by itself does not make a JSON text. See the RFC for more info: http://www.ietf.org/rfc/rfc4627.txt – Paul Jun 20 '13 at 22:55
  • @FishBasketGordo That being said parsers are allowed to parse more than just JSON texts, so it's perfectly valid for a parser to parse both JSON texts and single JSON values. It is not required to be a good parser though. – Paul Jun 20 '13 at 22:56
  • @FishBasketGordo Interestingly enough `JSON.stringify(1)` produces `'1'` which is not a valid JSON text. It should throw an error. – Paul Jun 20 '13 at 23:00
  • @Paulpro - In fact, Douglas Crockford once told me in an email that [a valid "JSON text" is an object or array only per the RFC](http://stackoverflow.com/a/16955349/1202830) - yet he wrote the original version of [JSON.js](https://github.com/douglascrockford/JSON-js/blob/master/json.js)! So I guess he's of two minds about it... – Michael Geary Jun 20 '13 at 23:23
  • Related if not duplicate: http://stackoverflow.com/q/18419428/11683 – GSerg Oct 08 '16 at 19:00

6 Answers6

14

Although 1 isn't a valid JSON object, it is a valid JSON number. It seems that $.parseJSON parses all JSON values, not just objects.

Jacob
  • 77,566
  • 24
  • 149
  • 228
13

Parsing a number

You can better handle the parsing of numbers using parseInt(). It will return a number on success and NaN (Not a Number) otherwise.

var a = parseInt('23');
isNan(a); // false

var b = parseInt('ab');
isNan(b); // true

Why it returns 1 in jQuery

If you have a look at the source of the jQuery method it will become clear very quickly.

  1. It will check if there is native support for JSON.parse.
  2. If not, it will create an anonymous function (with string body) that simply returns the data contained in the JSON string and calls it.

So if in your case step 2. is executed it will simply return 1 even though it's not real JSON.

UPDATE: I was curious how the native JSON.parse would handle it and it does the same thing (returning 1). So regardless of the implementation you always get the same result.

Library on display: http://code.jquery.com/jquery-1.8.3.js

parseJSON: function( data ) {
    if ( !data || typeof data !== "string") {
        return null;
    }

    // Make sure leading/trailing whitespace is removed (IE can't handle it)
    data = jQuery.trim( data );

    // Attempt to parse using the native JSON parser first
    if ( window.JSON && window.JSON.parse ) {
        return window.JSON.parse( data );
    }

    // Make sure the incoming data is actual JSON
    // Logic borrowed from http://json.org/json2.js
    if ( rvalidchars.test( data.replace( rvalidescape, "@" )
        .replace( rvalidtokens, "]" )
        .replace( rvalidbraces, "")) ) {

        return ( new Function( "return " + data ) )(); // Just returns JSON data.

    }
    jQuery.error( "Invalid JSON: " + data );
},
Bart
  • 17,070
  • 5
  • 61
  • 80
5

parseJSON actually just returns the JavaScript object from a well formed JSON string.

The JSON format accepts more than just (associative) arrays. It accepts data structures like:

  1. Objects
  2. Arrays
  3. Values
  4. Strings
  5. Numbers

Take a look at http://json.org/ for all the details concerning JSON.

$.parseJSON("1") actually reads a valid JavaScript number 1, resulting into 1.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
blowdoof
  • 141
  • 3
  • 2
    If you go to http://www.jslint.com/ advertised at the bottom of http://json.org and type in a `1` it will fail. To me that makes much sense since it's JavaScript **Object** Notation and number is not an object. Objects and arrays are. – Bart Jun 20 '13 at 22:23
  • Strange, since the JSON RFC (http://www.ietf.org/rfc/rfc4627.txt ) states in the introduction (par 1) that JSON can represent four primitive types (strings, numbers, booleans, and null) and two structured types (objects and arrays). – blowdoof Jun 21 '13 at 00:04
  • 2
    If you read a little but further you'll see `2. JSON Grammar` with the following: `A JSON text is a serialized object or array. JSON-text = object / array`. So I would think the introduction is a bit misleading. – Bart Jun 21 '13 at 08:14
  • 1
    Yes Bart, you're absolutely right, i've read the entire article, but justed wanted to point out that the RFC can be interpreted in several ways. I'd even say that an integer is an object as well, but that is out of the scope of this issue – blowdoof Jun 21 '13 at 19:01
  • @blowdoof There is no such thing as an integer in JSON, only numbers. And JSON numbers are not objects, they are values. – Paul Jun 21 '13 at 20:28
  • Update: [RFC 7159](https://tools.ietf.org/html/rfc7159) from March 2014, which obsoletes RFC 4627, allows the JSON text to be any JSON value, not just an object or an array. – Mark A. Fitzgerald Nov 12 '17 at 22:23
2

1 is not a valid "JSON text", but most JSON parsers accept it anyway. Not all do, as you found with jsonlint.

I posted a more complete explanation with information from the JSON RFC along with Douglas Crockford's opinion in response to another question.

Community
  • 1
  • 1
Michael Geary
  • 28,450
  • 9
  • 65
  • 75
0

This is how I parsed JSON invalidating numbers

try {
     // JSON.parse accepts numbers but we do not want to do that
     if (!isNaN(parseInt(inputState))) {
          throw "Invalid JSON.";
     }
          // there we have valid JSON without number
          let validJSON = JSON.parse(inputState);
} catch (error) {
   console.log(error)
}
Viljami
  • 639
  • 7
  • 15
0

I will try to answer it conceptually...

Json represents the value of a certain variable (without the variable name). If the variable is a structure, it will be represented by a Json structure. Same for array, and same for strings and numbers.

Since Json represents a value, you can use it the whole string as a value for a field in a struct, or as a cell in array.

There is a common misconception that Json stores multiple variables and their corresponding value. This is not the case. Json stores a single value, which could be a complex structure, or a simple integer.

Kapandaria
  • 533
  • 5
  • 9