preface
Json.stringify is a commonly used method in daily development. Can you really use it flexibly?
Before we move on to this article, Bao wants you to dive into Stringify with a few questions.
stringify
How many arguments does a function take?stringify
What are the serialization criteria?- What happens in function serialization?
Null, undefined, NaN
And so on special values?ES6
After the increase ofSymbol
The type,BigInt
Will there be special processing in the serialization process?
stringify
Why not deep copy?- You can think of that
stringify
The use of?
The context of the whole article is consistent with the following mind map, so you can make an impression.
Three parameters
In everyday programming, we often use the json.stringify method to convert an object to JSON string form.
const stu = {
name: 'zcxiaobao'.age: 18
}
// {"name":"zcxiaobao","age":18}
console.log(JSON.stringify(stu));
Copy the code
But is Stringify really that simple? Let’s take a look at the definition of stringify in MDN.
MDN points out that: The json.stringify () method converts a JavaScript object or value to a JSON string, optionally replacing the value if a replacer function is specified, or optionally containing only the properties specified by the array if the specified replacer is an array.
Does stringfy take more than one parameter? Of course, stringify takes three arguments.
Let’s take a look at the syntax and parameters of stringify:
JSON.stringify(value[, replacer [, space]])
Copy the code
value
: The value to be sequenced as a JSON string.replacer
(optional)- If the parameter is a function, each attribute of the serialized value is converted and processed by the function during serialization;
- If the argument is aAn array ofOnly the property names contained in the array will be serialized to the final
JSON
In a string - If the parameter is
null
Or not, all attributes of the object are serialized.
space
(Optional): Specifies a blank string for indentation to beautify the output- If the argument is a number, it represents how many Spaces there are. The upper limit is 10.
- If the value is less than 1, there are no Spaces
- If the parameter is a string (the first 10 characters are taken when the string is longer than 10 characters), the string will be used as a space
- If this parameter is not provided (or null), there will be no Spaces
replacer
Let’s try using replacer.
replacer
As a function
Replacer is a function that takes two arguments, a key and a value, and both arguments are serialized.
At the beginning, the replacer function is passed an empty string as a key value representing the object to be stringify. It is important to understand that the replacer function does not immediately parse the object into key-value pairs, but rather passes in the object to be serialized. The attributes on each object or array are then passed in sequence. If the function returns undefined or function, the attribute value will be filtered out, and the rest will follow the return rule.
// repalcer takes two arguments key value
// Key value is each key value pair of the object
// Thus we can do simple filtering based on the type of key or value
function replacer(key, value) {
if (typeof value === "string") {
return undefined;
}
return value;
}
// function can be tested by itself
function replacerFunc(key, value) {
if (typeof value === "string") {
return () = > {};
}
return value;
}
const foo = {foundation: "Mozilla".model: "box".week: 45.transport: "car".month: 7};
const jsonString = JSON.stringify(foo, replacer);
Copy the code
JSON serialization {“week”:45,”month”:7}
If the replacer function returns undefined or function, the current value will not be ignored and will be replaced by null.
const list = [1.'22'.3]
const jsonString = JSON.stringify(list, replacer)
Copy the code
JSON serialization results in ‘[1, NULL,3]’
replacer
As an array
Better understood as an array, filters the keys that appear in the array.
const foo = {foundation: "Mozilla".model: "box".week: 45.transport: "car".month: 7};
const jsonString = JSON.stringify(foo, ['week'.'month']);
Copy the code
The result of JSON serialization is {“week”:45,”month”:7}. Only the values of week and month are reserved.
Nine characteristics
Feature 1: undefined, function, Symbol value
- Appear in non-array object property values:
undefined
, arbitrary function,Symbol
Values will be captured during serializationignore - Appear in an array:
undefined
, arbitrary function,Symbol
The value will be converted to zeronull - When converted separately: undefined is returned
// 1. These three types of object attribute values are ignored
const obj = {
name: 'zc'.age: 18.// The function is ignored
sayHello() {
console.log('hello world')},// undefined is ignored
wife: undefined.// Symbol values are ignored
id: Symbol(111),
// [Symbol('zc')]: 'zc',
}
{"name":"zc","age":18}
console.log(JSON.stringify(obj));
// 2. The three values in the array are converted to NULL
const list = [
'zc'.18.// The function is converted to null
function sayHello() {
console.log('hello world')},// undefined converts to null
undefined.// Symbol converts to null
Symbol(111)]// ["zc",18,null,null,null]
console.log(JSON.stringify(list))
// 3. These three values converted separately will return undefined
console.log(JSON.stringify(undefined)) // undefined
console.log(JSON.stringify(Symbol(111))) // undefined
console.log(JSON.stringify(function sayHello() {
console.log('hello world')}))// undefined
Copy the code
Property 2: toJSON() method
If there is a toJSON() method, the serialized result returns the same value as the toJSON() method, and the rest of the values are ignored.
const obj = {
name: 'zc'.toJSON(){
return 'return toJSON'}}// return toJSON
console.log(JSON.stringify(obj));
Copy the code
Property three: Boolean, numeric, string wrapper object
Booleans, numbers, and string wrapper objects are automatically converted to their original values during serialization
JSON.stringify([new Number(1), new String("zcxiaobao"), new Boolean(true)]);
// [1,"zcxiaobao",true]
Copy the code
NaN Infinity NULL
Feature 4 focuses on special values in JavaScript, such as NaN and Infinity and NULL in Number. All three values are treated as NULL during serialization.
// [null,null,null,null,null]
JSON.stringify([null.NaN, -NaN.Infinity, -Infinity])
// Wrapping objects with Boolean values, numbers, and strings are automatically converted to their original values during serialization
// Implicit conversions call the wrapper class, so Number => NaN is called first
// Then convert to null
// 0/0 => Infinity => null
JSON.stringify([Number('123a'), +'123a'.0/0])
Copy the code
Feature 5: Date objects
The toJSON method (same as date.toisostring ()) is deployed on the Date object to convert it to a string, so json.stringify () will serialize the Date value into a time-format string.
/ / ": the 2022-03-06 T08 24:56. 138 z"
JSON.stringify(new Date())
Copy the code
Property 6: Symbol
When Symbol is used as a value, objects, arrays, and arrays alone are ignored, converted to NULL, and converted to undefined, respectively.
Similarly, all properties with Symbol as the property key are completely ignored, even if they are mandatory in the replacer parameter.
const obj = {
name: 'zcxiaobao'.age: 18[Symbol('lyl')]: 'unique'
}
function replacer(key, value) {
if (typeof key === 'symbol') {
returnvalue; }}// undefined
JSON.stringify(obj, replacer);
Copy the code
From the above example, we can see that although we specify the return Symbol value by replacer, it will be ignored.
Feature 7: BigInt
Json. stringify specifies that attempts to convert a value of type BigInt will raise TypeError
const bigNumber = BigInt(1)
// Uncaught TypeError: Do not know how to serialize a BigInt
console.log(JSON.stringify(bigNumber))
Copy the code
Feature 8: Circular reference
Property eight states that executing this method on objects that contain circular references (objects that refer to each other in an infinite loop) throws an error
Parse (json.stringify (obj))) is the simplest and most violent way to use deep copy in everyday development. However, deep copy under this method has a huge hole, and the key problem is that Stringify can’t handle circular references.
const obj = {
name: 'zcxiaobao'.age: 18,}const loopObj = {
obj
}
// Form a circular reference
obj.loopObj = loopObj;
JSON.stringify(obj)
/* Uncaught TypeError: Converting circular structure to JSON --> starting at object with constructor 'Object' | property 'loopObj' -> object with constructor 'Object' --- property 'obj' closes the circle at JSON.stringify (
) at
:10:6 */
Copy the code
Attribute 9: Enumerable properties
For serialization of objects (including Map/Set/WeakMap/WeakSet), Stringify also explicitly states that only enumerable properties will be serialized, in addition to some of the cases described above
// Non-enumerable attributes are ignored by default
// {"age":18}
JSON.stringify(
Object.create(
null,
{
name: { value: 'zcxiaobao'.enumerable: false },
age: { value: 18.enumerable: true}}));Copy the code
Six use
localStorage
The localStorage object is used to store data for an entire site for a long time, without expiration, until it is manually deleted. Usually we store it as objects.
- Just call
localStorage
Object methods
const obj = {
name: 'zcxiaobao'.age: 18
}
// Simply call localstorage.setitem ()
localStorage.setItem('zc', obj);
// The final result is [object object]
// Call localStorage failed
console.log(localStorage.getItem('zc'))
Copy the code
localStorage
Cooperate withJSON.stringify
methods
localStorage.setItem('zc'.JSON.stringify(obj));
{name: 'zcxiaobao', age: 18}
console.log(JSON.parse(localStorage.getItem('zc')))
Copy the code
Attribute filter
Imagine a scenario where the back end returns a long object with many properties, and we only need a few of them, and we want to store them in localStorage.
- Plan 1: Deconstruct assignment +
stringify
// We only need a,e,f attributes
const obj = {
a:1.b:2.c:3.d:4.e:5.f:6.g:7
}
// Destruct the assignment
const {a,e,f} = obj;
// Store to localStorage
localStorage.setItem('zc'.JSON.stringify({a,e,f}))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc'))
Copy the code
- use
stringify
的replacer
parameter
// Use replacer as an array for filtering
localStorage.setItem('zc'.JSON.stringify(obj, ['a'.'e'.'f']))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc'))
Copy the code
When a replacer is an array, it’s a nice trick to simply filter out the attributes we want.
Look before you leap
Parse (json.stringify) is one of the simplest and most violent ways to implement a deep copy of an object. But as the title suggests, use deep copy this way with great deliberation.
- Circular reference problem,
stringify
complains - The function,
undefined
,Symbol
Will be ignored NaN
,Infinity
和-Infinity
Will be serialized intonull
- .
Use json.parse (json.stringify) to make deep copies. Without these pitfalls, json.parse (json.stringify) is a viable deep-copy solution.
Object map function
When programming with arrays, we often use the map function. Once we have the replacer parameter, we can use this parameter to implement the object’s map function.
const ObjectMap = (obj, fn) = > {
if (typeoffn ! = ="function") {
throw new TypeError(`${fn}is not a function ! `);
}
// call json.stringify (obj, replacer) to implement map
// Then call json.parse to convert it back to an object
return JSON.parse(JSON.stringify(obj, fn));
};
// For example, multiply the value of the obj attribute by 2
const obj = {
a: 1.b: 2.c: 3
}
console.log(ObjectMap(obj, (key, val) = > {
if (typeof value === "number") {
return value * 2;
}
return value;
}))
Copy the code
Return value * 2; return value * 2;
As mentioned earlier, the replacer function first passes in the object to be serialized, and the object * 2 => NaN => toJSON(NaN) => undefined => is ignored and there is no further key-value pair parsing.
Deleting object Properties
With the replacer function, we can also delete certain attributes of an object.
const obj = {
name: 'zcxiaobao'.age: 18
}
// {"age":18}
JSON.stringify(obj, (key, val) = > {
// This property is ignored when the return value is undefined
if (key === 'name') {
return undefined;
}
return val;
})
Copy the code
Object to determine
Json.stringify can serialize objects as strings, so we can use string methods to implement simple object equality judgments.
// Check whether the array contains an object
const names = [
{name:'zcxiaobao'},
{name:'txtx'},
{name:'mymy'},];const zcxiaobao = {name:'zcxiaobao'};
// true
JSON.stringify(names).includes(JSON.stringify(zcxiaobao))
// Determine whether objects are equal
const d1 = {type: 'div'}
const d2 = {type: 'div'}
// true
JSON.stringify(d1) === JSON.stringify(d2);
Copy the code
Array objects are deduplicated
Using the above ideas, we can also implement simple array object decrement.
But since json.stringify serializes {x:1, y:1} and {y:1, x:1} differently, we need to deal with the objects in the array before we start.
- Method 1: Arrange the keys of each object in the array in lexicographical order
arr.forEach(item= > {
const newItem = {};
Object.keys(item) // Get the object key
.sort() // Sort by key
.map(key= > { // Generate a new object
newItem[key] = item[key];
})
// Use newItem to de-duplicate operations
})
Copy the code
Json.stringify provides a replacer array format parameter to filter the array.
- Method two: with the help of
replacer
The array format
function unique(arr) {
const keySet = new Set(a);const uniqueObj = {}
// Extract all keys
arr.forEach(item= > {
Object.keys(item).forEach(key= > keySet.add(key))
})
const replacer = [...keySet];
arr.forEach(item= > {
// All objects are replacer filtered according to the specified key value
unique[JSON.stringify(item, replacer)] = item;
})
return Object.keys(unique).map(u= > JSON.parse(u))
}
// Test it
unique([{}, {},
{x:1},
{x:1},
{a:1},
{x:1.a:1},
{x:1.a:1},
{x:1.a:1.b:1}])// Return the result[{}, {"x":1}, {"a":1}, {"x":1."a":1}, {"x":1."a":1."b":1}]
Copy the code
Refer to the link
- You don’t know the power of json.stringify ()
- Parse (json.stringify (obj)) the disadvantages of implementing deep copy
After the language
I am battlefield small bag, a fast growing small front end, I hope to progress together with you.
If you like xiaobao, you can pay attention to me in nuggets, and you can also pay attention to my small public number – Xiaobao learning front end.
All the way to the future!!