2.4.14.3 stringify ( value [ , replacer [ , space ] ] )

The stringify function returns a String in JSON format representing an ECMAScript value. It can take three parameters. The first parameter is required. 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 allow 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 an 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 replacer has a [[Call]] internal property, then

      1. Let ReplacerFunction be replacer.

    2. Else if the [[Class]] internal property of replacer is "Array", then

      1. Let PropertyList be an empty internal List.

      2. For each value v of a property of replacer that has an array index property name. The properties are enumerated in the ascending array index order of their names.

        1. Let item be undefined.

        2. If Type(v) is String then let item be v.

        3. Else if Type(v) is Object then,

          1. If the [[Class]] internal property of v is "String" or "Number", let item be ToString(v).

        4. If item is not undefined and item is not currently an element of PropertyList then,

          1. Append item to the end of PropertyList.

  5. If Type(space) is Object then,

    1. If the [[Class]] internal property of space is "Number" then,

      1. Let space be ToNumber(space).

    2. Else if the [[Class]] internal property of space is "String" then,

      1. Let space be ToString(space).

  6. If Type(space) is Number

    1. Let space be min(10, ToInteger(space)).

    2. Set gap to a String containing space space characters. This will be the empty String if space is less than 1.

  7. Else if Type(space) is String

    1. If the number of characters in space is 10 or less, set gap to space; otherwise, set gap to a String consisting of the first 10 characters of space.

  8. Else

    1. Set gap to the empty String.

  9. Let wrapper be a new object created as if by the expression new Object(), where Object is the standard built-in constructor with that name.

  10. Call the [[Put]] internal method of wrapper with arguments the empty String and value.

  11. Return the result of calling the abstract operation Str with the empty String and wrapper.

The abstract operation Str(key, holder) has access to ReplacerFunction from the invocation of the stringify method. Its algorithm is as follows:

  1. Let value be the result of calling the [[Get]] internal method of holder with argument key.

  2. If Type(value) is Object, then

    1. If value is a host object, return undefined.

    2. Let toJSON be the result of calling the [[Get]] internal method of value with argument "toJSON".

    3. If toJSON has a [[Call]] internal property

      1. Let value be the result of calling the [[Call]] internal method of toJSON, passing value as the this value and with an argument list consisting of key.

  3. If ReplacerFunction is not undefined, then

    1. Let value be the result of calling the [[Call]] internal method of ReplacerFunction, passing holder as the this value and with an argument list consisting of key and value.

  4. If Type(value) is Object, then

    1. If the [[Class]] internal property of value is "Number", then

      1. Let value be ToNumber(value).

    2. Else if the [[Class]] internal property of value is "String", then

      1. Let value be ToString(value).

    3. Else if the Class]] internal property of value is "Boolean", then

      1. Let value be the value of the [[Value]] internal property of value.

  5. If value is null then return "null".

  6. If value is true then return "true".

  7. If value is false then return "false".

  8. If Type(value) is String, then return the result of calling the abstract operation Quote with argument value.

  9. If Type(value) is Number

    1. If value is finite, return ToString(value).

    2. Else return "null".

  10. If Type(value) is Object, and value does not have a [[Call]] internal property

    1. If the [[Class]] internal property of value is "Array", then

      1. Return the result of calling the abstract operation JA with argument value.

    2. Else, return the result of calling the abstract operation JO with argument value.

  11. Return undefined.

The abstract operation Quote(value) wraps a String value in double quotation marks and escapes characters within it.

  1. Let product be the double quotation mark character.

  2. For each character C in value

    1. If C is the double quotation mark character or the backslash character

      1. Let product be the concatenation of product and the backslash character.

      2. Let product be the concatenation of product and C.

    2. Else if C is backspace, formfeed, newline, carriage return, or tab

      1. Let product be the concatenation of product and the backslash character.

      2. Let abbrev be the character corresponding to the value of C as follows:

        1. backspace        "b"

        2. formfeed          "f"

        3. newline            "n"

        4. carriage return "r"

        5. tab       "t"

      3. Let product be the concatenation of product and abbrev.

    3. Else if C is a control character having a code unit value less than the space character

      1. Let product be the concatenation of product and the backslash character.

      2. Let product be the concatenation of product and "u".

      3. Let hex be the result of converting the numeric code unit value of C to a String of four hexadecimal digits.

      4. Let product be the concatenation of product and hex.

    4. Else

      1. Let product be the concatenation of product and C.

  3. Let product be the concatenation of product and the double quotation mark character.

  4. Return product.

The abstract operation JO(value) serializes an object. It has access to the stack, indent, gap, PropertyList, ReplacerFunction, and space of the invocation of the stringify method.

  1. If stack contains value, raise a TypeError exception because the structure is cyclical.

  2. Append value to stack.

  3. Let stepback be indent.

  4. Let indent be the concatenation of indent and gap.

  5. If PropertyList is not undefined, then

    1. Let K be PropertyList.

  6. Else

    1. Let K be an internal List of Strings consisting of the names of all the own properties of value that do not have the DontEnum attribute. The ordering of the Strings should be the same as that used by the for-in statement.

      Note that JScript 5.x defines properties such that their DontEnum attribute is inherited from prototype properties with the same name. As a result of this, any own properties of value that have the same name as built-in properties that have the DontEnum attribute are not included in K.

  7. Let partial be an empty List.

  8. For each element P of K.

    1. Let strP be the result of calling the abstract operation Str with arguments P and value.

      1. If PropertyList is undefined and the call to Str caused new properties to be added to value, add the names of those properties to the end of K.

    2. If strP is not undefined

      1. Let member be the result of calling the abstract operation Quote with argument P.

      2. Let member be the concatenation of member and the colon character.

      3. If gap is not the empty String

        1. Let member be the concatenation of member and the space character.

      4. Let member be the concatenation of member and strP.

      5. Append member to partial.

  9. If partial is empty, then

    1. Let final be "{}".

  10. Else

    1. If gap is the empty String

      1. Let properties be a String formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with the comma character. A comma is not inserted either before the first String or after the last String.

      2. Let final be the result of concatenating "{", properties, and "}".

    2. Else if gap is not the empty String

      1. Let separator be the result of concatenating the comma character, the line feed character, and indent.

      2. Let properties be a String 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 result of concatenating "{", the line feed character, indent, properties, the line feed character, stepback, and "}".

  11. Remove the last element of stack.

  12. Let indent be stepback.

  13. Return final.

The abstract operation JA(value) serializes an array. It has access to the stack, indent, gap, and space of the invocation of the stringify method. The representation of arrays includes only the elements between zero and array.length – 1 inclusive. Named properties are excluded from the stringification. An array is stringified as an open left bracket, elements separated by commas, and a closing right bracket.

  1. If stack contains value, raise a TypeError exception because the structure is cyclical.

  2. Append value to stack.

  3. Let stepback be indent.

  4. Let indent be the concatenation of indent and gap.

  5. Let partial be an empty List.

  6. Let len be the result of calling the [[Get]] internal method of value with argument "length".

  7. Let index be 0.

  8. Repeat while index < len

    1. Let strP be the result of calling the abstract operation Str with arguments ToString(index) and value.

    2. If strP is undefined

      1. Append "null" to partial.

    3. Else

      1. Append strP to partial.

    4. Increment index by 1.

  9. If partial is empty, then

    1. Let final be "[]".

  10. Else

    1. If gap is the empty String

      1. Let properties be a String formed by concatenating all the element Strings of partial with each adjacent pair of Strings separated with the comma character. A comma is not inserted either before the first String or after the last String.

      2. Let final be the result of concatenating "[", properties, and "]".

    2. Else

      1. Let separator be the result of concatenating the comma character, the line feed character, and indent.

      2. Let properties be a String 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 result of concatenating "[", the line feed character, indent, properties, the line feed character, stepback, and "[".

  11. Remove the last element of stack.

  12. Let indent be stepback.

  13. Return final.

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, the stringify function must raise 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 raise 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 value is rendered in JSON text as the String false.

NOTE 3:

String values are wrapped in double quotes. The characters " and \ are escaped with \ prefixes. The characters " and \ are escaped with \ prefixes. Control characters are replaced with escape sequences \uHHHH, or with the shorter forms, \b (backspace), \f (formfeed), \n (newline), \r (carriage return), \t (tab).

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 an opening left brace followed by zero or more properties, separated with commas, closed with a right brace. A property is a quoted String representing the key or property name, a colon, and the stringified property value. An array is rendered as an opening left bracket followed by zero or more values, separated with commas, closed with a right bracket.

This is the end of the JSON specification text from the [ECMA-262/5] standard.