I have worked as an intern for 1 year, 965 for 1 year, and 996 for 2 years. If I count 3 years as less, it is not too much to say that I am a 4-year old driver. Json.stringify generally has the following uses:

  • Deep-copy: Deep-copy reference data
  • Serialization: server storage heavy dependence on the front end data, localStorage/sessionStorage data storage

But json.stringify has many more powerful features besides the two common uses above that are worth studying systematically. The point is that these are features you probably use a lot during development, but you just don’t know it.

If you think this is a boring, long usage post, let me give you a few interesting scenarios:

  • Why does this object have a property foo, but after being serialized and stored in the database persistently, the property is missing?
  • Why is it that when AXIos sends a POST request, if the body of the req contains a parameter with undefined value, it disappears in the request to the server?
  • Is the printed JSON string that hard to read? Besides store as a variable and parse, can we see the data structure clearly without parse?
  • Why serialize an object and it returns an error? Or are you quoting your own mistakes?

If these questions are confusing, be sure to read this blog post for the answers. You’re smart enough to figure it out.

  • Json.stringify () is commonly used in work
    • Parse (json.stringify (obj/arr))
    • Serialization: server storage heavy dependence on the front end data, localStorage/sessionStorage stored data (such as fabric. Js canvas template data, vue – amap SVG path information, and so on
      • Store data that focuses on front-end functions
      • LocalStorage and sessionStorage data storage
      • Query JSON data for parsing
  • First JSON. Stringify ()
    • Serialized data
    • Filter the data
    • Formatting data
  • Json.stringify (value, [,replacer[,space]]) syntax
    • parameter
      • value
      • Replacer (optional)
      • Space (optional)
    • The return value
    • abnormal
      • TypeError “cyclic object value”
      • TypeError “BigInt value can’t be serialized in JSON”
  • JSON. Stringify ()
    • Common Usage Notes
    • Replacer parameter
      • Parameters are functions
      • Parameter is array
    • Space parameters
      • Parameters for the number
      • Parameter is a string
    • The performance of the toJSON ()
  • Json.stringify () serializes a circular reference
    • A self-referential object throws TypeError
    • Json. stringify self-referent object in autonavi vue-amap
    • How do I serialize a self-referential object?
  • Does json.stringify () serialize objects with the same attributes and the same values but in a different order?
  • Examples of using josn.stringify () with localStorage
  • Answer the question at the beginning of the passage

Json.stringify () is commonly used in work

Parse (json.stringify (obj/arr))

const obj = {
    foo: 'hi'.bar: {
        name: 'bar'.age: 3
    },
    baz: ['hello'.'javascript']}const arr = ['hi', { name: 'bar'.age: 3},'hello'.'javascript']].const deepCopy = JSON.parse(JSON.stringify(obj/arr))
Copy the code

After deepCopy, deepCopy generates a memory-independent obj or arr. That is, obj/ ARR and deepCopy are stored in different heap memory. Changing obj/ ARR does not affect deepCopy, and changing deepCopy does not affect OBJ or ARR.

If you do not understand the depth of the copy, it is recommended to find information to learn systematically.

Serialization: server storage heavy dependence on the front end data, localStorage/sessionStorage data storage

The server stores data heavily dependent on the front end: for example, canvas template data for fabric.js, SVG path information for VUe-amap, and so on. LocalStorage and sessionStorage data: localStorage/sessionStorage The keys and The values are always strings.

Store data that focuses on front-end functions

For example, Canvas, SVG information, server to do persistence.

const complexFabricJSCanvasTemplate = { ... };
const complexVueAMapSVGObject = { ... };
const JSONStr = JSON.stringify(complexFabricJSCanvasTemplate/complexVueAMapSVGObject);
axios.post('/create', {
    name: 'fabric.js'.// "vue-amap"
    data: JSONStr,
  })
  .then((res) = >{
    console.log(res);
  })
  .catch((err) = >{
    console.log(err);
  });
Copy the code
LocalStorage and sessionStorage data storage
const testObj = {foo: 1.bar: 'hi'.baz: { name: 'frankkai'.age: 25 }}
localStorage.setItem('testObj'.JSON.stringify(testObj ));
Copy the code

GetItem (‘testObj’); localstorage.getitem (‘testObj’); // “[object Object]”

Query JSON data for parsing

The stored Canvas or SVG data is queried from the server interface and then transmitted to fabric.js and VUE-AMap for drawing after parsing.

return new Promise((resolve) = >{
    axios.get('/retrive', {
         name: 'fabric.js'.// "vue-amap"
    })
    .then((res) = >{
      const complexFabricJSCanvasTemplate = JSON.parse(res.result);
      const complexVueAMapSVGObject = JSON.parse(res.result);
      resolve(complexFabricJSCanvasTemplate/complexVueAMapSVGObject);
    })
    .catch((err) = >{
      console.log(err);
    });
})
Copy the code

First JSON. Stringify ()

  • The serialized data json.stringify () method converts a JS object or value to a JSON string.
  • Filter data If you specify replacer as an array or function, you can filter data.
  • Formatting data If you specify space, you can format a JSON string.

Serialized data

console.log(JSON.stringify({ x: 5.y: 6 }));
// expected output: "{"x":5,"y":6}"

console.log(JSON.stringify([new Number(3), new String('false'), new Boolean(false)));// expected output: "[3,"false",false]"

console.log(JSON.stringify({ x: [10.undefined.function(){}, Symbol(' ')]}));// expected output: "{"x":[10,null,null,null]}"

console.log(JSON.stringify(new Date(2006.0.2.15.4.5)));
/ / expected output: "" the 2006-01-02 T15:04:05. 000 z" "
Copy the code

Filter the data

var foo = {foundation: 'Mozilla'.model: 'box'.week: 45.transport: 'car'.month: 7};
// replacer is an array
JSON.stringify(foo, ['week'.'month']);  // '{"week":45,"month":7}', returns only week" and "month"
// replacer is a function
function replacer(key, value) {
  if (typeof value === 'string') return undefined;
  return value;
}
JSON.stringify(foo, replacer); // '{"week":45,"month":7}', return callback not undefined.
Copy the code

Formatting data

Indent the first line with two Spaces.

  • Two Spaces
  • The number 2
JSON.stringify({ a: 2 }, null.' ');
// JSON.stringify({a:2}, null, 2)
Copy the code

= >

"{
  "a": 2
}"
Copy the code

JSON.stringify(value, [ ,replacer[ ,space]]); grammar

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

parameter

value

To a JSON string value.

replacer

Filter data.

Function: replacer can be a function that returns undefined and does not output data. String arrays: A replacer can be an array, usually a string, or a number. Specifies the whitelist of attributes to output JSON. [‘ week ‘, ‘month’]. Null or No write: When replacer is null or no write, all attributes are printed. Null is used when space is set without filtering data.

Is replacer’s array a number? [1, 2, 3, 4, 5]?

const arr = { 999: 'hi'.foo: 'js'.bar:' java' };
JSON.stringify(arr, [999.'foo']); // Prints out "{"999":"hi","foo":"js"}". Here 999 is of type number.
Copy the code
space

Indented Spaces or padding strings to enhance readability.

  • String or number specifies how many Spaces to insert.
  • Number Maximum minimum Blank number. The maximum value of number is 10. If the value is greater than 10, set the value to 10. Less than 1 means no indentation is required.
  • String Indicates the maximum or minimum blank value. The first 10 characters of a string. If the value is greater than 10, the first 10 characters are selected.
  • Null or No write Not Indent If the value is null or no write, the lock is not locked by default.

The return value

JSON string.

abnormal

TypeError “cyclic object value”

This error is reported when serializing a self-referenced object. Segments on Amap are self-referencing objects. How to serialize self-referenced objects can be seen below.

TypeError “BigInt value can’t be serialized in JSON”

Obj that contains a BitInt that exceeds the Number store limit cannot be serialized.

JSON.stringify({foo: 1n}) // TypeError "BigInt value can't be serialized in JSON"
Copy the code

JSON. Stringify ()

Common Usage Notes

If you want to get the best out of json.stringify (), here are some tips to follow.

  • ToJSON method If the serialized value has a toJSON() method, you can define how the data is serialized.
  • After serialization, the Boolean, Number, and String data types are preserved. This conversion conforms to traditional semantics.
  • Does not support convert undefined, the function, the SymbolThese types are not valid JSON values. If it is common, it is ignored.If found in an array, it is cast to NULL.Json.stringify (function(){}) or json.stringify (undefined) returns undefined.JSON.stringify({ foo: Symbol('foo') }); / / "{}"
  • When the Symbol type is used as the key, it is completely ignored.Even if it is explicitly specified in the replacer.JSON.stringify({ [Symbol('foo')]: 'foo' }); // '{}' JSON.stringify({ [Symbol.for('foo')]: 'foo' }, [Symbol.for('foo')]); / / '{}'
  • When the Date type is the value. The toJSON method for Date is equivalent to date.toisostring ().
  • Special types: Infinity, NaN, undefined, null Infinity, NaN, undefined, and null are treated as null.
  • Special types: Map, Set, WeakMap, WeakSetAll other Object instances (Map, Set, WeakMap, WeakSet) only Enumerable can be serialized. These values are Enumerable false by default.var foo = [['foo',1]]; var mp = new Map(foo); JSON.stringify(mp); / / "{}"
  • An array’s String property cannot be enumerable. let a = ['foo', 'bar']; a['baz'] = 'quux'; // a: [ 0: 'foo', 1: 'bar', baz: 'quux' ]; JSON.stringify(a); // '["foo","bar"]'
  • TypedArray types can be serialized. JSON.stringify([new Float32Array([1]), new Float64Array([1])]); / / '[{" 0 ": 1}, {" 0" : 1}]'

Extreme use examples:

JSON.stringify({});                    / / '{}'
JSON.stringify(true);                  // 'true'
JSON.stringify('foo');                 // '"foo"'
JSON.stringify([1.'false'.false]);   // '[1,"false",false]'
JSON.stringify([NaN.null.Infinity]); // '[null,null,null]'
JSON.stringify({ x: 5 });              // '{"x":5}'

JSON.stringify(new Date(2006.0.2.15.4.5)) 
/ / '" 2006-01-02 T15:04:05. 000 z "'

JSON.stringify({ x: 5.y: 6 });
// '{"x":5,"y":6}'
JSON.stringify([new Number(3), new String('false'), new Boolean(false)]);
// '[3,"false",false]'

// String-keyed array elements are not enumerable and make no sense in JSON
let a = ['foo'.'bar'];
a['baz'] = 'quux';      // a: [ 0: 'foo', 1: 'bar', baz: 'quux' ]
JSON.stringify(a); 
// '["foo","bar"]'

JSON.stringify({ x: [10.undefined.function(){}, Symbol(' ')]});// '{"x":[10,null,null,null]}' 

// Standard data structures
JSON.stringify([new Set([1]), new Map([[1.2]]), new WeakSet([{a: 1}]), new WeakMap([[{a: 1}, 2]])]);
/ / '[{}, {}, {}, {}]'

// TypedArray
JSON.stringify([new Int8Array([1]), new Int16Array([1]), new Int32Array([1]]);/ / '[{" 0 ": 1}, {" 0" : 1}, {" 0 ": 1}]'
JSON.stringify([new Uint8Array([1]), new Uint8ClampedArray([1]), new Uint16Array([1]), new Uint32Array([1]]);/ / '[{" 0 ": 1}, {" 0" : 1}, {" 0 ": 1}, {" 0" : 1}]'
JSON.stringify([new Float32Array([1]), new Float64Array([1]]);/ / '[{" 0 ": 1}, {" 0" : 1}]'
 
// toJSON()
JSON.stringify({ x: 5.y: 6, toJSON(){ return this.x + this.y; }});/ / '11'

// Symbols:
JSON.stringify({ x: undefined.y: Object.z: Symbol(' ')});/ / '{}'
JSON.stringify({ [Symbol('foo')]: 'foo' });
/ / '{}'
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

// Non-enumerable properties:
JSON.stringify( Object.create(null, { x: { value: 'x'.enumerable: false }, y: { value: 'y'.enumerable: true}}));// '{"y":"y"}'


// BigInt values throw
JSON.stringify({x: 2n});
// TypeError: BigInt value can't be serialized in JSON
Copy the code

Replacer parameter

Replacer can be function or array.

function
function replacer(key="", value) {
    return value;
}
Copy the code

As function, there are two parameters key and value. By default, the replacer function has a key of “” and is called once for each value in the object.

`function replacer(key,value){ return value; } JSON.stringify({foo: false,bar:123},replacer); `
Copy the code

The return value can be:

  • Number The string attribute associated with number is added.return 123; / / "123"
  • The string attribute associated with string is added.return "foo"; // "foo"
  • Boolean “true” or “false” is added.return true; // "true"
  • Null “NULL” was added.return null; //"null"
  • Value If it is a normal value object, its properties are recursively serialized into a JSON string. //return value;" {"foo":false,"bar":123}"
  • Undefined does not return this property. //JSON.stringify({foo: false,bar:undefined},replacer);" {" foo ": false}".

The use of powerful undefined is worth noting:

  1. undefined For those of you who have used Axios, here’s the catch: when the reqBody of our POST request contains undefined, it doesn’t send to the server interface at all, whereas null does. This is theJSON.stringify()The credit. v = JSON.stringify(v)Values of the undefined type are automatically filtered out.
// axios source buildurl.js line 37~56:
  utils.forEach(params, function serialize(val, key) {
      if (utils.isArray(val)) {
        key = key + '[]';
      } else {
        val = [val];
      }

      utils.forEach(val, function parseValue(v) {
        if (utils.isDate(v)) {
          v = v.toISOString();
        } else if (utils.isObject(v)) {
          v = JSON.stringify(v); // Notice here
        }
        parts.push(encode(key) + '=' + encode(v));
      });
    });
Copy the code
  1. Replacer cannot be used to remove array values. If undefined, null is returned.
function replacer(key,value){
    if(typeof value ==='boolean') {return undefined}
    return value;
}
JSON.stringify([1.'false'.false],replacer);
// "[1,"false",null]"
Copy the code
Commonly used way
function replacer(key, value) {
  // Return undefined filter attribute
  if (typeof value === 'string') {
    return undefined;
  }
  return value;
}

var foo = {foundation: 'Mozilla'.model: 'box'.week: 45.transport: 'car'.month: 7};
JSON.stringify(foo, replacer); // '{"week":45,"month":7}'
Copy the code
JSON.stringify(foo, ['week'.'month']);  // '{"week":45,"month":7}', 
Copy the code

Space parameters

  • It could be a number up to 10,10 indents
  • It can be a string with up to 10 char indents
JSON.stringify({ a: 2 }, null.' ');
{/ / '
// "a": 2
// 
JSON.stringify({ uno: 1.dos: 2 }, null.'\t');
// returns the string:
{/ / '
// "uno": 1,
// "dos": 2
/ /} '
Copy the code

The performance of the toJSON ()

If the object to be stringed has a property called toJSON whose value is a function, the toJSON() method will customize the JSON stringing behavior: Instead of serializing the object, the value returned by the toJSON() method will be serialized, not the serialized object. Json.stringify () calls toJSON with one argument:

  • If this object is an attribute value, the attribute name is returned
  • If it is in an array, return the index in the array (as a string)
  • If json.stringify () is called directly on this object, an empty string is returned
var obj = {
    data: 'data',
    toJSON (key) {
        returnkey; }};JSON.stringify(obj);
/ / "" "" "
JSON.stringify({ obj })
// '{"obj":"'obj'"}'
JSON.stringify([ obj ])
/ / '[] "' 0 '"'
Copy the code

Json.stringify () serializes a circular reference

A self-referential object throws TypeError

TypeError: Converting circular structure to JSON

const circularReference = {};
circularReference.myself = circularReference;
// Serializing circular references throws "TypeError: cyclic object value"
JSON.stringify(circularReference);
Copy the code

Json. stringify self-referent object in autonavi vue-amap

Path planning SVG information segments object for plans.

The requirement is that the front end needs to pass information about the route to the back end, including an array of latitude and longitude and an SVG array. Serializing latitude and longitude arrays with json.stringify () is OK, but serializing SVG arrays is self-referential and will report errors. (I later learned that this SVG array can not be saved to the server, but at that time serialization error was really confused)

How do I serialize a self-referential object?

Use Douglas Crockford’s cycle.js

It adds two new methods to the global JSON object:

  • Json.decycle (attributes that will self-referencemyself:objReplace withmyself:{$ref: "$"})
  • JSON.retrocycle

Example:

var circularReference = {};
circularReference.myself = circularReference;
JSON.decycle(circularReference);
// { "$ref": "$" }
Copy the code

Does json.stringify () serialize objects with the same attributes and the same values but in a different order?

Is not equal.

var a = JSON.stringify({ foo: "bar".baz: "quux" })
//'{"foo":"bar","baz":"quux"}'
var b = JSON.stringify({ baz: "quux".foo: "bar" })
//'{"baz":"quux","foo":"bar"}'
console.log(a === b) // false
Copy the code

Examples of using josn.stringify () with localStorage

LocalStorage can only store string data, so you need to serialize objects to JSON strings using json.stringify ().

var session = {
  'screens': [].'state': true
};
session.screens.push({ 'name': 'screenA'.'width': 450.'height': 250 });
session.screens.push({ 'name': 'screenB'.'width': 650.'height': 350 });
session.screens.push({ 'name': 'screenC'.'width': 750.'height': 120 });
localStorage.setItem('session'.JSON.stringify(session));
var restoredSession = JSON.parse(localStorage.getItem('session'));
console.log(restoredSession);
Copy the code

Answer the question at the beginning of the passage

Why does this object have a property foo, but after being serialized and stored in the database persistently, the property is missing?

Value is undefined? Did replacer filter it? Is it filtered in the toJSON method? Property enumerable is false? Symbol? The Map? The Set? WeakMap? WeakSet? Find out why.

Why is it that when AXIos sends a POST request, if the body of the req contains a parameter with undefined value, it disappears in the request to the server?

v = JSON.stringify(v); // v = {foo: undefined} =>"{}"
Copy the code

The source code is in buildurl.js lines 37~56

Is the printed JSON string that hard to read? Besides store as a variable and parse, can we see the data structure clearly without parse?

const testObj = {foo: 1.bar: 'hi'.baz: { name: 'frankkai'.age: 25 }}
JSON.stringify(testObj, null.4);
Copy the code

= >

"{
    "foo": 1,
    "bar": "hi",
    "baz": {
        "name": "frankkai",
        "age": 25
    }
}"
Copy the code

Why serialize an object and it returns an error? Or are you quoting your own mistakes? Can’t this object be serialized?

This is because after a self-reference, the loop is restricted. The engine should have done something special to automatically throw an exception when it found this infinite loop. Can’t this object be serialized? You can use cycle.js’s decycle(serialization).

var circularReference = {};
circularReference.myself = circularReference;
JSON.decycle(circularReference);
// { "$ref": "$" }
Copy the code

References:

  • Developer.mozilla.org/en-US/docs/…
  • Github.com/douglascroc…
  • Developer.mozilla.org/en-US/docs/…
  • Github.com/axios/axios…

I am looking forward to communicating with you and making progress together. Welcome to join the technical discussion group I created which is closely related to front-end development:

  • SegmentFault technosphere :ES new specification syntax sugar
  • SegmentFault column: Be a good front-end engineer while you’re still young
  • Zhihu column: Be an excellent front-end engineer while you are still young
  • Github blog: Personal blog 233 while You’re Still Young
  • Front-end development QQ group: 660634678
  • excellent_developers

Strive to be an excellent front-end engineer!