JSON.stringify to fy them all

For today, a deeper look at the well known JavaScript JSON.stringify function. The function usually used to converts JavaScript object into JSON string clone object and more.

Allow me to start with a simple detailed example to show all the conversion types.

JSON.stringify({
    "string":    'string',      // "string"
    "number":    1,             // 1
    "bool":      true,          // true
    "null":      null,          // null
    "undefuned": undefined,     // REMOVED FROM OUTPUT
    "function":  function(){},  // REMOVED FROM OUTPUT
    "object":    {},            // {}
    "date:       Date()         // "Wed May 29 2019 15:45:44...
    "emptyArry":[               // []
    "arry":[                     
        1,                      // 1
        null,                   // null
        undefined,              // null
        function(){}            // null
 ]});

Note the different ways object and array are handling types that are not value: The object will remove undefined and functions while array will convert them to nulls.

JSON.stringify({a: null, b: undefined, c: function(){}});
// -> "{"a":null}"

JSON.stringify([null, undefined, function(){}])
// -> [null,null,null]

Object with toJSON function

If the object has toJSON function than this will be used as the stringified value of the object instead of the JSON itself.

JSON.stringify({
   some_hidden_data: 'you will never see me',
   toJSON : ()=> 'ha ha, fake value'
});

// ""ha ha, fake value""

Half practical example:

let hidePassword = function(){}
hidePassword.prototype.toJSON = function(){
   return {…this,password:'****'}
}

let me = new hidePassword();
me.name = 'Krishindow';
me.age = 87;
me.password = 'youWillNeverGuessIt';

JSON.stringify(me);
// "{"name":"Krishindow","age":87,"password":"****"}"

circular references

The only built-in error inside JavaScript JSON.stringify will happen if the JSON has circular references:

let a = {
     me : 'this is a'
 }
 let b = {
     me : 'this is b'
     a:a}
 a.b = b
 a.b.a.b.a.me;   // "this is a"
 a.b.a.b.a.b.me; // "this is b"
 
JSON.stringify(a)
 //VM756:1 Uncaught TypeError: Converting circular structure to JSON

Replacer

The second value on the stringify function is the replacer. It can be a function or an array. The replacer filters or modifies the output.

Array replacer

let abc = {
     a:"a",
     b:"b",
     c:"c"
 };

JSON.stringify(abc);           // "{"a":"a","b":"b","c":"c"}"
JSON.stringify(abc,["a","c"]); // "{"a":"a","c":"c"}"

To make it a little more interesting…

let me = {
    name:  "Koshoboo",
    age:   87,
    degree:"PHD",
    hobby: "Looking as the grass grow"
}
const sayAtTheBar = ['name','hobby'],
      tellTheMotherInLow = ['name','degree'];

let location = 'atTheBar';
if(location == 'withTheMotherInLow'){
    JSON.stringify(me,sayAtTheBar);
}else{
    JSON.stringify(me,tellTheMotherInLow);
}
fixTheDamage();

A real use will be using ENUM of arrays to expose the relevant values to each use: the server, the view, and so on.

Function replacer

The replacer can be a function. That way you can modify the value of a property or remove it by replacing it with undefined.

let me = {
   name: 'Jankirah',
   _hobby: 'Chasing cats',
   _password: 'YouWillNeverKnow'
}

function removePrivate(key, value) {
  return key.includes('_')? undefined : value;
}

function hidePassword(key, value) {
  return key.includes("password") ? "****": value;
}

JSON.stringify(me, removePrivate);
// "{"name":"Jankirah"}"

JSON.stringify(me, hidePassword);
// "{"name":"Jankirah","_hobby": "Chasing cats","_password":"****"}"

Space

The third and last property is “space”. Passing a number will determine the amount of space added before each property at a maximum of 10.

JSON.stringify({
     a:'a',
     b:'b'
 }, null);
//"{"a":"a","b":"b"}"

JSON.stringify({
     a:'a',
     b:'b'
 }, null,15);
/*
 "{
          "a": "a",
          "b": "b"
 }"
*/

Passing a string will add the value before each property, with a limit of 10 characters

JSON.stringify({
      a:'a',
      b:{
         b1:'b1',
         b2:'b2'
     }
  }, null,' <----> ');
/*
"{
  <----> "a": "a",
  <----> "b": {
  <---->  <----> "b1": "b1",
  <---->  <----> "b2": "b2"
  <--**--> }
 }"
*/

Sometimes you found yourself astonished, finding small options that were sitting there all the time, just laughing at you, while you’re trying to reinvent the wheel. This is one of them and!