JSON.stringify replacer array semantics

Oliver Hunt oliver at apple.com
Thu Jun 4 16:01:38 PDT 2009


The spec for JSON doesn't describe the exact behaviour of the replacer  
argument to stringify when the replacer is an array.  The relevant  
text (from 15.12.3) is

If Type(replacer) is object and the [[Class]] internal property of  
replacer is "Array", then
     Let K be an internal List consisting of the values of those  
properties of replacer that have array index names. The elements of  
the list are in ascending array index order.

As the replacer array may contain any sequence of values we need to  
specify the acceptance, conversion, and conversion timing for each  
element.  The spec doesn't really specify these details at all, saying  
only that replacer may be an array of strings.

Two issues that need to be clarified (that i can see):
    * What happens if the replacer array is modified during  
serialisation?
    * What happens to non-string primitives are in the replacer array?

json2.js basically seems to do something akin to the following if  
replacer is an array
    givenReplacer = replacer;
    replacer = [];
    var length = replacer.length;
    for (var i = 0; i < length; i++) {
        if (typeof givenReplacer[i] === "string")
            replacer.push(givenReplacer[i]);
    }

This resolves the above issues by making a copy of the array (thus  
isolating it from mutation of the replacer array), and resolves the  
non-string property issue by just ignoring any non-string values.  I  
believe it would be more consistent with ECMAScript to perform  
[[ToString]] conversion instead of filtering non-string values, but if  
we do that we need to specify when the [[ToString]] conversion should  
occur.  I believe that at the beginning of the stringify algorithm,  
probably just before what is currently step 7 (where the wrapper is  
created)

7. If Type(replacer) is object and the [[Class]] internal property of  
replacer is "Array", then
     a. Let oldReplacer be replacer
     b. Let replacer be a new array
     c. Let len be the result of calling the [[Get]] internal method  
of oldReplacer with argument "length"
     d. Let index be 0
     e. Repeat while index < len
         i. Let prop be the result of calling the [[Get]] internal  
method of oldReplacer with argument index
         ii. Let prop be the result of calling the method ToString(prop)
         iii. if prop is not undefined
             A. Call the [[Put]] internal method of replacer with  
arguments index and prop
         iv. Increment  index by 1

Remaining steps 7, 8, and 9 move to 8, 9,  and 10

--Oliver



More information about the es-discuss mailing list