Json.stringify is a function we often use in our daily development. For example, it can be used to process the body parameter in POST requests, store object objects in localStorage, or even implement a simple deep copy.

However, it is such a common JS official function, but there are some little people know the secret. Today, let’s find out.

Secret 1: Beautify the output

Many of you probably know this. Json.stringify takes a parameter to beautify the output and make it more readable.

By default, json.stringify prints the serialized result as a single line. But when a third argument, space, is provided, json.stringify takes a single line for each key and prefixes the key with space.

Space can be a number or a string.

const obj = { a: 1.b: { c: 2}}JSON.stringify(obj)
// "{"a":1,"b":{"c":2}}"

JSON.stringify(obj, null.2)
{/ /"
// "a": 1,
// "b": {
// "c": 2
/ /}
// }"

JSON.stringify(obj, null.'* *')
{/ /"
// **"a": 1,
// **"b": {
// ****"c": 2
/ / * *}
// }"
Copy the code

Secret 2: The magicreplacer

The second parameter is null. Don’t worry, just listen to me.

The second argument to json.stringify is called replacer. It can be a list or a function.

ifreplacerIs a list of

When a replacer is a list, it acts like a whitelist, with the final result containing only the key in the list key: value.

const user = {
    name: 'Hopsken'.website: 'https://hopsken.com'.password: 'SUPER_SECRET',}JSON.stringify(user, ['name'.'website'].2)
{/ /"
// "name": "Hopsken",
// "website": "https://hopsken.com"
// }"
Copy the code

It is worth noting that the key names in the final result are arranged in the order in which they are listed.

JSON.stringify(user, ['website'.'name'].2)
{/ /"
// "website": "https://hopsken.com",
// "name": "Hopsken"
// }"
    
// You can even do that
const config = { ... }
JSON.stringify(config, Object.keys(config).sort(), 2)
Copy the code

ifreplacerIs the function

When replacer is a function, JS calls this function on each key-value pair during serialization and uses the return value of the function as the value corresponding to the key.

const obj = { a: 1.b: { c: 2}}JSON.stringify(obj, (key, value) => {
    if (typeof value === 'number') {
        return value + 1;
    }
    return value;
}, 2)
{/ /"
// "a": 2,
// "b": {
// "c": 3
/ /}
// }"
Copy the code

If the return value is undefined, the value is ignored in the final result. (This is expected behavior, since undefined is not a value in the JSON standard format).

const user = {
    name: 'Hopsken'.password: 'SUPER_SECRET',}JSON.stringify(user, (key, value) => {
    if (key.match(/password/i)) {
        return undefined;
    }
    return value;
}, 2)
{/ /"
// "name": "Hopsken"
// }"
Copy the code

Secret 3: Self-control what needs to be output

Json.stringify’s third secret! When json.stringify () attempts to serialize an object, it first iterates over the object to see if it has the toJSON() property. If so, json.stringify () will serialize the value returned by this function instead of the original object.

Simply put, the toJSON() method defines what values will be serialized.

With the toJSON() method, we can control the behavior of json.stringify () ourselves.

Here’s an example:

const movie = {
    title: 'Let the bullets fly'.year: 2010.stars: new Set([Chow Yun-fat.'I'.'ge you']),
    toJSON() {
        return {
            name: `The ${this.title} The ${this.year}`.actors: [... this.stars]
        }
    }
}

JSON.stringify(movie, null.2)
{/ /"
// "name": "Let the bullets fly 2010",
// "actors": [
// "Chow Yun Fat ",
//
// ""
/ /]
// }"
Copy the code

In the example above, we used the toJSON property to enable json.stringify () to serialize Set data.

It’s worth noting that this in toJSON refers to objects at the current level and is scoped only to objects at the current level.

const user = {
    name: 'Hospken'.wechat: {
        name: 'FEMinutes',
        toJSON() {
            return `WX: The ${this.name}`; }}},JSON.stringify(user, null.2)
{/ /"
// "name": "Hospken",
// "wechat": "WX: FEMinutes"
// }"
Copy the code

As you can see, wechat. ToJSON () only applies to the wechat attribute.

Bonus: Use for listsJSON.stringify ?

So we know that the list in JS is also object. It stands to reason that json.stringify should also work on lists.

First, let’s try the default parameters.

const arr = ["apple"."orange"."banana"]

JSON.stringify(arr)
// "["apple","orange","banana"]"
Copy the code

Everything is normal.

Try the space argument again:

const arr = ["apple"."orange"."banana"]

JSON.stringify(arr, null.2)
/ /"
// "apple",
// "orange",
// "banana"
/ /"
Copy the code

Perfect!

The replacer?

const arr = ["apple"."orange"."banana"]

JSON.stringify(arr, (key, value) => {
	return `one ${value}`
}, 2)
// ""one apple,orange,banana""
Copy the code

Cool cool, it seems not ok ah… It appears that the replacer function was executed only once, rather than the expected three times. However, json.stringify () is not intended to be used this way either, and unexpected results are normal.

But it doesn’t matter, we have toJSON()! Let’s try it:

const arr = ["apple"."orange"."banana"]
arr.toJSON = function() {
	return this.slice().map(val= > `one ${val}`)}JSON.stringify(arr, null.2)
/ /"
// "apple",
// "orange",
// "banana"
/ /"
Copy the code

So we implement replacer via toJSON(). Isn’t it beautiful?

The end of the

So that’s the end of today’s mystery. We won’t go into the details of how json.stringify () handles boundary cases (such as circular references) because of space constraints.

Thanks for watching. See you next time

The resources

JSON.stringify() – MDN

ECMAScript 2015 (6th Edition, ECMA-262)

The 80/20 Guide to JSON.stringify in JavaScript

The secret power of JSON stringify