Chapter 08 Exercise Set 1

  1. Write a function called serializeJSON which, when given a JavaScript value, produces a string with the value’s JSON representation. Simple values like numbers and booleans can be simply given to the String function to convert them to a string. Objects and arrays can be handled by recursion.

    Recognizing arrays can be tricky, since its type is "object". You can use instanceof Array, but that only works for arrays that were created in your own window ― others will use the Array prototype from other windows, and instanceof will return false. A cheap trick is to convert the constructor property to a string, and see whether that contains "function Array".

    When converting a string, you have to take care to escape special characters inside it. If you use double-quotes around the string, the characters to escape are \", \\, \f, \b, \n, \t, \r, and \v.

    Note

    We already saw \n, which is a newline. \t is a tab character, \r a ‘carriage return’, which some systems use before or instead of a newline to indicate the end of a line. \b (backspace), \v (vertical tab), and \f (form feed) are useful when working with old printers, but less so when dealing with Internet browsers.

    function serializeJSON(value) {
        function isArray(value) {
            return /^\s*function Array/.test(String(value.constructor));
        }
    
        function serializeArray(value) {
            return "[" + map(serializeJSON, value).join(", ") + "]";
        }
        function serializeObject(value) {
            var properties = [];
            forEachIn(value, function(name, value) {
                properties.push(serializeString(name) + ": " +
                                serializeJSON(value));
            });
            return "{" + properties.join(", ") + "}";
        }
        function serializeString(value) {
            var special =
                 {"\"": "\\\"", "\\": "\\\\", "\f": "\\f", "\b": "\\b",
                  "\n": "\\n", "\t": "\\t", "\r": "\\r", "\v": "\\v"};
            var escaped = value.replace(/[\"\\\f\b\n\t\r\v]/g,
                                      function(c) {return special[c];});
            return "\"" + escaped + "\"";
        }
    
        var type = typeof value;
        if (type == "object" && isArray(value))
            return serializeArray(value);
        else if (type == "object")
            return serializeObject(value);
        else if (type == "string")
            return serializeString(value);
        else
            return String(value);
    }
    
    alert(serializeJSON(fruit));
    

    The trick used in serializeString is similar to what we saw in the escapeHTML function in Regular Expressions. It uses an object to look up the correct replacements for each of the characters. Some of them, such as "\\\\", look quite weird because of the need to put two backslashes for every backslash in the resulting string.

    Also note that the names of properties are quoted as strings. For some of them, this is not necessary, but for property names with spaces and other strange things in them it is, so the code just takes the easy way out and quotes everything.