foreword
A bug was encountered in the project. In order to retain a JSON object, a component uses JSON.stringify to convert it into a string. Of course, this is to avoid the pollution of the data source caused by the object being a reference type.
However, after using the JSON.parse method later, I found 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}
As you can see, Infinity becomes null, which leads to the following bug. In fact, there are already many pits in the project to step on JSON.stringify. I will take this opportunity to sort it out and give you a reference.
Let's talk about the solution to this problem first:
Workaround 1:
Simple and rude, re-assign the age attribute
Workaround 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;
}
);
This is a bit of a detour. As a reference, I actually used the first method directly. But here you can see that JSON.stringify actually has a second parameter, so what's the use of it? Next we unveil its mystery.
JSON.stringify basic syntax
JSON.stringify(value[, replacer [, space]])
concept
The MDN Chinese documentation 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 a function specified, or optionally replacing the value if replacer is specified as an array Include only the properties specified by the array.
I personally think that this interpretation is inappropriate, the inappropriateness is "object or array", because in fact, for ordinary values, we can also use JSON.stringify, but we rarely use it. However, this problem is not big, and what we introduce in this article is also for objects or arrays.
JSON.stringify('foo'); // '"foo"'
The English version of MDN's explanation will be much more reasonable:
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.
In simple terms, JSON.stringify() converts a value to the corresponding JSON format string.
JSON.stringify powerful second parameter replacer
This parameter is optional and can be a function or an array
When it is a function, during the serialization process, each property that is serialized will be converted and processed by the function, see the following code:
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"}
This is actually a filtering function, which uses the feature that the property value of the object in JSON.stringify is undefined and will be ignored in serialization (we will mention it later).
It is worth noting that at the beginning, the replacer function will be passed an empty string as the key value, representing the object to be stringified.
The values output by console.log(key, value) above are as follows:
{ name: 'Gopal', age: 25, like: 'FE' }
name Gopal
age 25
like FE
{"age":25,"like":"FE"}
It can be seen that through the second parameter, we can operate and modify the value of the serialized target more flexibly.
When the second parameter is an array, only the property names contained in the array will be serialized:
JSON.stringify(myIntro, ['name']) // {"name":"Gopal"}
The third parameter of the fancy
Specify a blank string for indentation, and more often specify a number to represent 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"
// }
JSON.stringify usage scenarios
Check if object/array values are equal
let a = [1,2,3],
b = [1,2,3];
JSON.stringify(a) === JSON.stringify(b);// true
localStorage/sessionStorage storage objects
We know that localStorage/sessionStorage can only store strings. When we want to store objects, we need to use JSON.stringify to convert them into strings, and then JSON.parse them when we get them.
// 存
function setLocalStorage(key,val) {
window.localStorage.setItem(key, JSON.stringify(val));
};
// 取
function getLocalStorage(key) {
let val = JSON.parse(window.localStorage.getItem(key));
return val;
};
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' }
Route (browser address) parameter
Because browser parameters can only be passed through strings, JSON.stringify is also required.
Notes on using JSON.stringify
After reading the above, do you think JSON.stringify is very powerful, and immediately want to try it in the project? Wait a moment, read the following precautions before making a decision, it may trigger some difficult-to-find problems in some scenarios.
There is a toJSON method in the conversion attribute value, use it with caution
If there is a toJSON method in the converted value, the value returned by this method will be the final serialization result.
// toJSON
let toJsonMyIntro = {
name: "Gopal",
age: 25,
like: "FE",
toJSON: function () {
return "前端杂货铺";
},
};
console.log(JSON.stringify(toJsonMyIntro)); // "前端杂货铺"
There are undefined, arbitrary functions and symbol values in the converted value, use with caution
There are two cases:
One is an array object, undefined, arbitrary functions and symbol values will be converted to null.
JSON.stringify([undefined, Object, Symbol("")]);
// '[null,null,null]'
One is a non-array object, which is ignored during serialization.
JSON.stringify({ x: undefined, y: Object, z: Symbol("") });
// '{}'
For this case, we can use the second parameter of JSON.stringify to make it meet our expectations
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)"}
Objects containing circular references, use with caution
let objA = {
name: "Gopal",
}
let objB = {
age: 25,
}
objA.age = objB
objB.name = objA
JSON.stringify(objA)
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
Attributes with symbol as attribute key, use with caution
All properties with symbol as property 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
Values are NaN and Infinity, use with caution
Array values, or non-array object property values 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]
Use with caution when having non-enumerable property values
Non-enumerable properties 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"}
Summarize
JSON.stringify is indeed very convenient to solve many of our problems in practical applications, such as simple deep copying and so on.
However, when we use it, we also need to know its shortcomings. In the case that the target value may be some special value, the result after serialization may not meet our expectations. At this time, we need to use it with caution.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。