25.5 The JSON Object

The JSON object:

  • is %JSON%.
  • is the initial value of the "JSON" property of the global object.
  • is an ordinary object.
  • contains two functions, parse and stringify, that are used to parse and construct JSON texts.
  • has a [[Prototype]] internal slot whose value is %Object.prototype%.
  • does not have a [[Construct]] internal method; it cannot be used as a constructor with the new operator.
  • does not have a [[Call]] internal method; it cannot be invoked as a function.

The JSON Data Interchange Format is defined in ECMA-404. The JSON interchange format used in this specification is exactly that described by ECMA-404. Conforming implementations of JSON.parse and JSON.stringify must support the exact interchange format described in the ECMA-404 specification without any deletions or extensions to the format.

25.5.1 JSON.parse ( text [ , reviver ] )

The parse function parses a JSON text (a JSON-formatted String) and produces an ECMAScript value. The JSON format represents literals, arrays, and objects with a syntax similar to the syntax for ECMAScript literals, Array Initializers, and Object Initializers. After parsing, JSON objects are realized as ECMAScript objects. JSON arrays are realized as ECMAScript Array instances. JSON strings, numbers, booleans, and null are realized as ECMAScript Strings, Numbers, Booleans, and null.

The optional reviver parameter is a function that takes two parameters, key and value. It can filter and transform the results. It is called with each of the key/value pairs produced by the parse, and its return value is used instead of the original value. If it returns what it received, the structure is not modified. If it returns undefined then the property is deleted from the result.

  1. Let jsonString be ? ToString(text).
  2. Parse ! StringToCodePoints(jsonString) as a JSON text as specified in ECMA-404. Throw a SyntaxError exception if it is not a valid JSON text as defined in that specification.
  3. Let scriptString be the string-concatenation of "(", jsonString, and ");".
  4. Let script be ParseText(! StringToCodePoints(scriptString), Script).
  5. Assert: script is a Parse Node.
  6. Let completion be the result of evaluating script. The extended PropertyDefinitionEvaluation semantics defined in B.3.1 must not be used during the evaluation.
  7. Let unfiltered be completion.[[Value]].
  8. Assert: unfiltered is either a String, Number, Boolean, Null, or an Object that is defined by either an ArrayLiteral or an ObjectLiteral.
  9. If IsCallable(reviver) is true, then
    1. Let root be ! OrdinaryObjectCreate(%Object.prototype%).
    2. Let rootName be the empty String.
    3. Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered).
    4. Return ? InternalizeJSONProperty(root, rootName, reviver).
  10. Else,
    1. Return unfiltered.

The "length" property of the parse function is 2𝔽.

Note

Valid JSON text is a subset of the ECMAScript PrimaryExpression syntax. Step 2 verifies that jsonString conforms to that subset, and step 8 asserts that that parsing and evaluation returns a value of an appropriate type.

However, because B.3.1 applies when evaluating ECMAScript source text and does not apply during JSON.parse, the same source text can produce different results when evaluated as a PrimaryExpression rather than as JSON. Furthermore, the Early Error for duplicate "__proto__" properties in object literals, which likewise does not apply during JSON.parse, means that not all texts accepted by JSON.parse are valid as a PrimaryExpression, despite matching the grammar.

25.5.1.1 InternalizeJSONProperty ( holder, name, reviver )

The abstract operation InternalizeJSONProperty takes arguments holder (an Object), name (a String), and reviver (a function object). It performs the following steps when called:

Note 1

This algorithm intentionally does not throw an exception if either [[Delete]] or CreateDataProperty return false.

  1. Let val be ? Get(holder, name).
  2. If Type(val) is Object, then
    1. Let isArray be ? IsArray(val).
    2. If isArray is true, then
      1. Let I be 0.
      2. Let len be ? LengthOfArrayLike(val).
      3. Repeat, while I < len,
        1. Let prop be ! ToString(𝔽(I)).
        2. Let newElement be ? InternalizeJSONProperty(val, prop, reviver).
        3. If newElement is undefined, then
          1. Perform ? val.[[Delete]](prop).
        4. Else,
          1. Perform ? CreateDataProperty(val, prop, newElement).
        5. Set I to I + 1.
    3. Else,
      1. Let keys be ? EnumerableOwnPropertyNames(val, key).
      2. For each String P of keys, do
        1. Let newElement be ? InternalizeJSONProperty(val, P, reviver).
        2. If newElement is undefined, then
          1. Perform ? val.[[Delete]](P).
        3. Else,
          1. Perform ? CreateDataProperty(val, P, newElement).
  3. Return ? Call(reviver, holder, « name, val »).

It is not permitted for a conforming implementation of JSON.parse to extend the JSON grammars. If an implementation wishes to support a modified or extended JSON interchange format it must do so by defining a different parse function.

Note 2

In the case where there are duplicate name Strings within an object, lexically preceding values for the same key shall be overwritten.

25.5.2 JSON.stringify ( value [ , replacer [ , space ] ] )

The stringify function returns a String in UTF-16 encoded JSON format representing an ECMAScript value, or undefined. It can take three parameters. The value parameter is an ECMAScript value, which is usually an object or array, although it can also be a String, Boolean, Number or null. The optional replacer parameter is either a function that alters the way objects and arrays are stringified, or an array of Strings and Numbers that acts as an inclusion list for selecting the object properties that will be stringified. The optional space parameter is a String or Number that allows the result to have white space injected into it to improve human readability.

These are the steps in stringifying an object:

  1. Let stack be a new empty List.
  2. Let indent be the empty String.
  3. Let PropertyList and ReplacerFunction be undefined.
  4. If Type(replacer) is Object, then
    1. If IsCallable(replacer) is true, then
      1. Set ReplacerFunction to replacer.
    2. Else,
      1. Let isArray be ? IsArray(replacer).
      2. If isArray is true, then
        1. Set PropertyList to a new empty List.
        2. Let len be ? LengthOfArrayLike(replacer).
        3. Let k be 0.
        4. Repeat, while k < len,
          1. Let prop be ! ToString(𝔽(k)).
          2. Let v be ? Get(replacer, prop).
          3. Let item be undefined.
          4. If Type(v) is String, set item to v.
          5. Else if Type(v) is Number, set item to ! ToString(v).
          6. Else if Type(v) is Object, then
            1. If v has a [[StringData]] or [[NumberData]] internal slot, set item to ? ToString(v).
          7. If item is not undefined and item is not currently an element of PropertyList, then
            1. Append item to the end of PropertyList.
          8. Set k to k + 1.
  5. If Type(space) is Object, then
    1. If space has a [[NumberData]] internal slot, then
      1. Set space to ? ToNumber(space).
    2. Else if space has a [[StringData]] internal slot, then
      1. Set space to ? ToString(space).
  6. If Type(space) is Number, then
    1. Let spaceMV be ! ToIntegerOrInfinity(space).
    2. Set spaceMV to min(10, spaceMV).
    3. If spaceMV < 1, let gap be the empty String; otherwise let gap be the String value containing spaceMV occurrences of the code unit 0x0020 (SPACE).
  7. Else if Type(space) is String, then
    1. If the length of space is 10 or less, let gap be space; otherwise let gap be the substring of space from 0 to 10.
  8. Else,
    1. Let gap be the empty String.
  9. Let wrapper be ! OrdinaryObjectCreate(%Object.prototype%).
  10. Perform ! CreateDataPropertyOrThrow(wrapper, the empty String, value).
  11. Let state be the Record { [[ReplacerFunction]]: ReplacerFunction, [[Stack]]: stack, [[Indent]]: indent, [[Gap]]: gap, [[PropertyList]]: PropertyList }.
  12. Return ? SerializeJSONProperty(state, the empty String, wrapper).

The "length" property of the stringify function is 3𝔽.

Note 1

JSON structures are allowed to be nested to any depth, but they must be acyclic. If value is or contains a cyclic structure, then the stringify function must throw a TypeError exception. This is an example of a value that cannot be stringified:

a = [];
a[0] = a;
my_text = JSON.stringify(a); // This must throw a TypeError.
Note 2

Symbolic primitive values are rendered as follows:

  • The null value is rendered in JSON text as the String "null".
  • The undefined value is not rendered.
  • The true value is rendered in JSON text as the String "true".
  • The false value is rendered in JSON text as the String "false".
Note 3

String values are wrapped in QUOTATION MARK (") code units. The code units " and \ are escaped with \ prefixes. Control characters code units are replaced with escape sequences \uHHHH, or with the shorter forms, \b (BACKSPACE), \f (FORM FEED), \n (LINE FEED), \r (CARRIAGE RETURN), \t (CHARACTER TABULATION).

Note 4

Finite numbers are stringified as if by calling ToString(number). NaN and Infinity regardless of sign are represented as the String "null".

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.

Note 6

An object is rendered as U+007B (LEFT CURLY BRACKET) followed by zero or more properties, separated with a U+002C (COMMA), closed with a U+007D (RIGHT CURLY BRACKET). A property is a quoted String representing the key or property name, a U+003A (COLON), and then the stringified property value. An array is rendered as an opening U+005B (LEFT SQUARE BRACKET followed by zero or more values, separated with a U+002C (COMMA), closed with a U+005D (RIGHT SQUARE BRACKET).

25.5.2.1 SerializeJSONProperty ( state, key, holder )

The abstract operation SerializeJSONProperty takes arguments state, key, and holder. It performs the following steps when called:

  1. Let value be ? Get(holder, key).
  2. If Type(value) is Object or BigInt, then
    1. Let toJSON be ? GetV(value, "toJSON").
    2. If IsCallable(toJSON) is true, then
      1. Set value to ? Call(toJSON, value, « key »).
  3. If state.[[ReplacerFunction]] is not undefined, then
    1. Set value to ? Call(state.[[ReplacerFunction]], holder, « key, value »).
  4. If Type(value) is Object, then
    1. If value has a [[NumberData]] internal slot, then
      1. Set value to ? ToNumber(value).
    2. Else if value has a [[StringData]] internal slot, then
      1. Set value to ? ToString(value).
    3. Else if value has a [[BooleanData]] internal slot, then
      1. Set value to value.[[BooleanData]].
    4. Else if value has a [[BigIntData]] internal slot, then
      1. Set value to value.[[BigIntData]].
  5. If value is null, return "null".
  6. If value is true, return "true".
  7. If value is false, return "false".
  8. If Type(value) is String, return QuoteJSONString(value).
  9. If Type(value) is Number, then
    1. If value is finite, return ! ToString(value).
    2. Return "null".
  10. If Type(value) is BigInt, throw a TypeError exception.
  11. If Type(value) is Object and IsCallable(value) is false, then
    1. Let isArray be ? IsArray(value).
    2. If isArray is true, return ? SerializeJSONArray(state, value).
    3. Return ? SerializeJSONObject(state, value).
  12. Return undefined.

25.5.2.2 QuoteJSONString ( value )

The abstract operation QuoteJSONString takes argument value. It wraps value in 0x0022 (QUOTATION MARK) code units and escapes certain other code units within it. This operation interprets value as a sequence of UTF-16 encoded code points, as described in 6.1.4. It performs the following steps when called:

  1. Let product be the String value consisting solely of the code unit 0x0022 (QUOTATION MARK).
  2. For each code point C of ! StringToCodePoints(value), do
    1. If C is listed in the “Code Point” column of Table 61, then
      1. Set product to the string-concatenation of product and the escape sequence for C as specified in the “Escape Sequence” column of the corresponding row.
    2. Else if C has a numeric value less than 0x0020 (SPACE), or if C has the same numeric value as a leading surrogate or trailing surrogate, then
      1. Let unit be the code unit whose numeric value is that of C.
      2. Set product to the string-concatenation of product and UnicodeEscape(unit).
    3. Else,
      1. Set product to the string-concatenation of product and ! UTF16EncodeCodePoint(C).
  3. Set product to the string-concatenation of product and the code unit 0x0022 (QUOTATION MARK).
  4. Return product.
Table 61: JSON Single Character Escape Sequences
Code Point Unicode Character Name Escape Sequence
U+0008 BACKSPACE \b
U+0009 CHARACTER TABULATION \t
U+000A LINE FEED (LF) \n
U+000C FORM FEED (FF) \f
U+000D CARRIAGE RETURN (CR) \r
U+0022 QUOTATION MARK \"
U+005C REVERSE SOLIDUS \\

25.5.2.3 UnicodeEscape ( C )

The abstract operation UnicodeEscape takes argument C (a code unit). It represents C as a Unicode escape sequence. It performs the following steps when called:

  1. Let n be the numeric value of C.
  2. Assert: n ≤ 0xFFFF.
  3. Return the string-concatenation of:
    • the code unit 0x005C (REVERSE SOLIDUS)
    • "u"
    • the String representation of n, formatted as a four-digit lowercase hexadecimal number, padded to the left with zeroes if necessary

25.5.2.4 SerializeJSONObject ( state, value )

The abstract operation SerializeJSONObject takes arguments state and value. It serializes an object. It performs the following steps when called:

  1. If state.[[Stack]] contains value, throw a TypeError exception because the structure is cyclical.
  2. Append value to state.[[Stack]].
  3. Let stepback be state.[[Indent]].
  4. Set state.[[Indent]] to the string-concatenation of state.[[Indent]] and state.[[Gap]].
  5. If state.[[PropertyList]] is not undefined, then
    1. Let K be state.[[PropertyList]].
  6. Else,
    1. Let K be ? EnumerableOwnPropertyNames(value, key).
  7. Let partial be a new empty List.
  8. For each element P of K, do
    1. Let strP be ? SerializeJSONProperty(state, P, value).
    2. If strP is not undefined, then
      1. Let member be QuoteJSONString(P).
      2. Set member to the string-concatenation of member and ":".
      3. If state.[[Gap]] is not the empty String, then
        1. Set member to the string-concatenation of member and the code unit 0x0020 (SPACE).
      4. Set member to the string-concatenation of member and strP.
      5. Append member to partial.
  9. If partial is empty, then
    1. Let final be "{}".
  10. Else,
    1. If state.[[Gap]] is the empty String, then
      1. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with the code unit 0x002C (COMMA). A comma is not inserted either before the first String or after the last String.
      2. Let final be the string-concatenation of "{", properties, and "}".
    2. Else,
      1. Let separator be the string-concatenation of the code unit 0x002C (COMMA), the code unit 0x000A (LINE FEED), and state.[[Indent]].
      2. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with separator. The separator String is not inserted either before the first String or after the last String.
      3. Let final be the string-concatenation of "{", the code unit 0x000A (LINE FEED), state.[[Indent]], properties, the code unit 0x000A (LINE FEED), stepback, and "}".
  11. Remove the last element of state.[[Stack]].
  12. Set state.[[Indent]] to stepback.
  13. Return final.

25.5.2.5 SerializeJSONArray ( state, value )

The abstract operation SerializeJSONArray takes arguments state and value. It serializes an array. It performs the following steps when called:

  1. If state.[[Stack]] contains value, throw a TypeError exception because the structure is cyclical.
  2. Append value to state.[[Stack]].
  3. Let stepback be state.[[Indent]].
  4. Set state.[[Indent]] to the string-concatenation of state.[[Indent]] and state.[[Gap]].
  5. Let partial be a new empty List.
  6. Let len be ? LengthOfArrayLike(value).
  7. Let index be 0.
  8. Repeat, while index < len,
    1. Let strP be ? SerializeJSONProperty(state, ! ToString(𝔽(index)), value).
    2. If strP is undefined, then
      1. Append "null" to partial.
    3. Else,
      1. Append strP to partial.
    4. Set index to index + 1.
  9. If partial is empty, then
    1. Let final be "[]".
  10. Else,
    1. If state.[[Gap]] is the empty String, then
      1. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with the code unit 0x002C (COMMA). A comma is not inserted either before the first String or after the last String.
      2. Let final be the string-concatenation of "[", properties, and "]".
    2. Else,
      1. Let separator be the string-concatenation of the code unit 0x002C (COMMA), the code unit 0x000A (LINE FEED), and state.[[Indent]].
      2. Let properties be the String value formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with separator. The separator String is not inserted either before the first String or after the last String.
      3. Let final be the string-concatenation of "[", the code unit 0x000A (LINE FEED), state.[[Indent]], properties, the code unit 0x000A (LINE FEED), stepback, and "]".
  11. Remove the last element of state.[[Stack]].
  12. Set state.[[Indent]] to stepback.
  13. Return final.
Note

The representation of arrays includes only the elements between zero and array.length - 1 inclusive. Properties whose keys are not array indexes are excluded from the stringification. An array is stringified as an opening LEFT SQUARE BRACKET, elements separated by COMMA, and a closing RIGHT SQUARE BRACKET.

25.5.3 JSON [ @@toStringTag ]

The initial value of the @@toStringTag property is the String value "JSON".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.