preface

A bug was encountered in the project where a component used json.stringify to convert a JSON object to a string in order to keep a copy of the object, in order to avoid contamination of the data source if the object was of a reference type.

But when you use the json.parse method later, you see that the data has changed.

Code simplification:

let obj = {
  name: 'Gopal'.age: Infinity
}
let originObj = JSON.stringify(obj)
console.log(originObj) // {"name":"Gopal","age":null}
Copy the code

As you can see, Infinity is null, which causes the following bug. In fact, the project on their own json. stringify pit has been a lot of, take this opportunity to tidy up, but also to give you a reference

Solution 1:

Simply, re-assign the age attribute

Solution 2:

function censor(key, value) {
  if (value === Infinity) {
    return "Infinity";
  }
  return value;
}
var b = JSON.stringify(a, censor);

var c = JSON.parse(
  b,
  function (key, value) {
    return value === "Infinity"  ? Infinity: value; });Copy the code

This is a little confusing, but for reference, I actually used the first method directly. But you can see here that json.stringify actually has a second argument, so what’s the use of that? Now let’s uncover the mystery of it.

Json. stringify Basic syntax

JSON.stringify(value[, replacer [, space]])
Copy the code

concept

The MDN Chinese document explains it as follows:

The json.stringify () method converts a JavaScript value ** (object or array) ** to a JSON string, optionally replacing the value if replacer is specified as a function, or if replacer is specified as an array, Optionally include only the properties specified by the array.

Personally, I think it’s a bit of a snag. The snag is “object or array”, because we can actually use json.stringify for normal values, but we rarely do. But that’s not a big problem, and everything we do in this article is for objects or arrays.

JSON.stringify('foo');   // '"foo"'
Copy the code

The English version makes much more sense

The JSON.stringify() method converts a JavaScript object or value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.

Simply put, json.stringify () converts the value to the corresponding JSON-formatted string.

Json. stringify powerful second parameter replacer

This argument is optional and can be either a function or an array

In the case of a function, each property that is serialized is converted and processed by the function during the serialization process.

let replacerFun = function (key, value) {
  console.log(key, value)
  if (key === 'name') {
    return undefined
  }
  return value
}

let myIntro = {
  name: 'Gopal'.age: 25.like: 'FE'
}

console.log(JSON.stringify(myIntro, replacerFun))
// {"age":25,"like":"FE"}
Copy the code

This is actually a filter, using the json. stringify feature where an object property with undefined is ignored in serialization (we’ll see later).

Note that at first the replacer function is passed an empty string as the key value, representing the object to be stringify

The output values of console.log(key, value) are as follows:

 { name: 'Gopal'.age: 25.like: 'FE' }
name Gopal
age 25
like FE
{"age":25."like":"FE"}
Copy the code

As you can see, with the second parameter, we have more flexibility to manipulate and modify the value of the serialized target

When the second argument is an array, only the property names contained in the array will be serialized

JSON.stringify(myIntro, ['name']) // {"name":"Gopal"}
Copy the code

The third parameter that looks useless

Specifies a string of whitespace to use for indentation, or more often, a number representing several Spaces:

let myIntro = {
  name: 'Gopal'.age: 25.like: 'FE'
}

console.log(JSON.stringify(myIntro))
console.log(JSON.stringify(myIntro, null.2))

// {"name":"Gopal","age":25,"like":"FE"}
/ / {
// "name": "Gopal",
// "age": 25,
// "like": "FE"
// }
Copy the code

Json. stringify Usage scenario

Determines whether the object/array values are equal

letA = [1,2,3], b = [1,2,3]; JSON.stringify(a) === JSON.stringify(b); //true
Copy the code

LocalStorage and sessionStorage storage object

We know that localStorage/sessionStorage can store only string, when we want to store objects, you need to use JSON. The stringify converted to string, when get JSON. The parse

/ / save
function setLocalStorage(key,val) {
    window.localStorage.setItem(key, JSON.stringify(val));
};
/ /
function getLocalStorage(key) {
    let val = JSON.parse(window.localStorage.getItem(key));
    return val;
};
Copy the code

Implement object deep copy

let myIntro = {
  name: 'Gopal'.age: 25.like: 'FE'
}

function deepClone() {
  return JSON.parse(JSON.stringify(myIntro))
}

let copyMe = deepClone(myIntro)
copyMe.like = 'Fitness'
console.log(myIntro, copyMe)

// { name: 'Gopal', age: 25, like: 'FE' } { name: 'Gopal', age: 25, like: 'Fitness' }
Copy the code

Route (browser address) pass parameter

Since browser arguments can only be passed through strings, json.stringify is also required

Json. stringify Usage considerations

See above, feel JSON. Stringify function is very powerful, immediately attempt to in the project? Wait a while and read the following DOS and don ‘ts before you make a decision, which in some cases may trigger some undiscoverable problems

Use the toJSON method in the transform property value with caution

If there is a toJSON method in the transform value, the value returned by that method will be the final serialized result

// toJSON
let toJsonMyIntro = {
  name: "Gopal".age: 25.like: "FE".toJSON: function () {
    return "Front end grocery store."; }};console.log(JSON.stringify(toJsonMyIntro)); // "Front end grocery"
Copy the code

Use with caution if the converted value contains undefined, arbitrary functions, and symbol values

There are two cases

One is an array object, where undefined, any function, and symbol values are converted to NULL

JSON.stringify([undefined.Object.Symbol("")]);
// '[null,null,null]'
Copy the code

A non-array object that is ignored during serialization

JSON.stringify({ x: undefined.y: Object.z: Symbol("")});/ / '{}'
Copy the code

In this case, we can use the second argument of json.stringify to make it what we expect

const testObj = { x: undefined.y: Object.z: Symbol("test")}const resut = JSON.stringify(testObj, function (key, value) {
  if (value === undefined) {
    return 'undefined'
  } else if (typeof value === "symbol" || typeof value === "function") {
    return value.toString()
  }
  return value
})

console.log(resut)
// {"x":"undefined","y":"function Object() { [native code] }","z":"Symbol(test)"}
Copy the code

Objects that contain circular references. Use with caution

let objA = {
  name: "Gopal",}let objB = {
  age: 25,
}

objA.age = objB
objB.name = objA
JSON.stringify(objA)

Copy the code

The following error will be reported:

Uncaught TypeError: Converting circular structure to JSON
    --> starting at object with constructor 'Object'
    |     property 'age' -> object with constructor 'Object'
    --- property 'name' closes the circle
    at JSON.stringify (<anonymous>)
    at <anonymous>:1:6
Copy the code

Use with caution an attribute whose attribute key is symbol

All properties with symbol as the attribute key are completely ignored, even if they are mandatory in the replacer parameter.

JSON.stringify({ [Symbol.for("foo")]: "foo" }, [Symbol.for("foo")])
// '{}'

JSON.stringify({ [Symbol.for("foo")]: "foo" }, function (k, v) {
  if (typeof k === "symbol") {
    return "a symbol";
  }
})
// undefined
Copy the code

Values NaN and Infinity, use with caution

Array values, or non-array object properties with NaN and Infinity values, are converted to NULL

let me = {
  name: "Gopal".age: Infinity.money: NaN};let originObj = JSON.stringify(me);
console.log(originObj); // {"name":"Gopal","age":null,"money":null}

JSON.stringify([NaN.Infinity])
// [null,null]
Copy the code

Use this parameter with caution when there is an attribute value that cannot be enumerated

Properties that cannot be enumerated are ignored by default:

let person = Object.create(null, {
  name: { value: "Gopal".enumerable: false },
  age: { value: "25".enumerable: true}})console.log(JSON.stringify(person))
// {"age":"25"}
Copy the code

conclusion

Json. stringify is a convenient solution to many of our problems, such as simple deep copy. However, when we use it, we also need to know what disadvantages it has. If the target value is some special value, the serialized result may not meet our expectations, so we need to use it with caution

reference

JSON.stringify converting Infinity to null

MDN JSON.stringify()

Json.stringify (), and the difference between json.stringify() and json.parse()

You don’t know the power of json.stringify ()

I hope to be able to give you a little inspiration, but also welcome you to pay attention to my public number, and look forward to communication and growth with you