Execute Program

Modern JavaScript: Customizing JSON Serialization

Welcome to the Customizing JSON Serialization lesson!

This lesson is shown as static text below. However, it's designed to be used interactively. Click the button below to start!

  • JSON.stringify takes a JavaScript object or value as its argument, and turns it into JSON. We can customize its output by passing a second argument, replacer. For example, if we pass an array of strings as the replacer, then only keys names in the array will be included in the resulting object.

  • >
    JSON.parse(
    JSON.stringify(
    {age: 36, city: 'Paris', name: 'Amir'},
    ['name', 'city']
    )
    );
    Result:
  • The replacer can also be a callback function taking two arguments, key and value. During stringification, our replacer is called with the key and value for each object, array, string, etc. We can replace any value by simply returning the new value that should take its place.

  • In the next code example, we see this in action by logging the replacer's arguments at each step. Pay extra attention to the first logged line, where the overall object is passed to us with a key of "". (Execute Program will show the console output, so you don't need to open your browser's built-in development console.)

  • >
    JSON.stringify(
    {age: 36, name: 'Amir', cat: {name: 'Ms. Fluff'}},
    (key, value) => {
    console.log(`Key: ${JSON.stringify(key)}, value: ${JSON.stringify(value)}`);
    return value;
    }
    );
    console output
  • The first replacer call gets the entire object. The key is "" because we're not inside of an object yet. Then we see separate calls for the age, name, and cat keys. Finally, stringify descends into the cat object, so we get a final call for its name key. We didn't replace any data in this example, but we could've replaced the data in any of these steps, from the entire object down to a single deeply nested property.

  • At each step, our replacer function can do three things:

    • Return the value argument unmodified, which won't change the stringified object.
    • Return some other value, which will replace the original value in the stringified JSON.
    • Return undefined, which will remove the key from the stringified JSON.
  • >
    JSON.parse(
    JSON.stringify(
    {name: 'Amir', catName: 'Ms. Fluff'},
    (key, value) => {
    if (typeof value === 'string') {
    return 'New ' + value;
    } else {
    return value;
    }
    }
    )
    );
    Result:
  • >
    JSON.parse(
    JSON.stringify(
    {catName: 'Ms. Fluff', city: 'Paris', name: 'Amir'},
    (key, value) => {
    if (key === 'catName') {
    return undefined;
    } else {
    return value;
    }
    }
    )
    );
    Result:
    {city: 'Paris', name: 'Amir'}Pass Icon
  • There's even more detail to the replacer function, but we won't cover its other functionality here. If you need to write a JSON.stringify replacer, you should definitely have the documentation open anyway! The important thing to know is that this function exists, and that the replacer gets a chance to modify every part of the object as it's stringified. That should help you decide when it's appropriate to use.

  • Finally, JSON.parse has a similar feature called reviver. As the JSON is decoded, the reviver can replace any value with a new value.

  • >
    JSON.parse(
    '{"name": "Amir"}'
    );
    Result:
    {name: 'Amir'}Pass Icon
  • >
    JSON.parse(
    '{"name": "Amir", "age": 36}',
    (key, value) => {
    if (key === 'age' && value === 36) {
    return 'thirty-six';
    } else {
    return value;
    }
    }
    );
    Result:
    {name: 'Amir', age: 'thirty-six'}Pass Icon
  • >
    /* Note that the "reviver" function here replaces all property values in
    * the object! */
    JSON.parse(
    '{"name": "Amir", "age": 36}',
    (key, value) => {
    if (key === '') {
    return value;
    } else {
    return 'nevermind';
    }
    }
    );
    Result:
    {name: 'nevermind', age: 'nevermind'}Pass Icon
  • Reviver and replacer functions give us fine-grained control around stringifying and parsing data with JSON. This can be helpful when decoding third-party data whose format you don't control, or when formatting your own data to be shared as JSON. However, always consider whether the data transformation should be done separately, rather than in a replacer or reviver function. Often, transforming the data separately makes code easier to read.