JSON replacer is recursive. This then means it uses the same array for all objects it comes across. In other words, it uses the same values to map BAD.g's value. Since, Bad.g's value does not have any keys matching the ones you provided, nothing will get mapped properly. This means we have to add "2" to your array. Now "2" also has an object with different keys. We have already accounted for "b", so now we just need to add "w" to your array.

When providing an array to the replacer, best to think of the array as a list of all the keys you want mapped.

DEMO: http://jsfiddle.net/dirtyd77/whv7x6xc/4/

console.log(JSON.stringify(BAD, ['a', 'b', 'c', 'd', 'e', 'g', '2', 'w']));

Hope this helps and let me know if you have any questions.


Here is also a snippet from the documentation,

If you return any other object, the object is recursively stringified into the JSON string, calling the replacer function on each property, unless the object is a function, in which case nothing is added to the JSON string.


In the case for dynamic keys, you can always create a function to push to an array and use that array for your whitelist. Here is an example:

DEMO: http://jsfiddle.net/dirtyd77/whv7x6xc/5/

var BAD = {
    "a": "2",
    "b": 1,
    "c": "Nexus",
    "d": "Alligator",
    "e": 5,
    "f": 1431807036,
    "g": {
        "2": {
            "w": 17,
            "b": 5
        }
    }
}

var whitelist = [];

iterate(BAD);

console.log(whitelist, JSON.stringify(BAD, whitelist));

function iterate(obj){
    for(var key in obj){
        // may have to do some checking to ignore any keys you don't care about
        whitelist.push(key);
        // if value is an object, will use this same function to push to whitelist array
        if(typeof obj[key] === 'object'){
            return iterate(obj[key]);
        }
    }
}

You can also just use your existing whitelist and just append keys on your g key (given that isn't dynamic):

DEMO: http://jsfiddle.net/dirtyd77/whv7x6xc/6/

var whitelist = ['a', 'b', 'c', 'd', 'e', 'g'];

iterate(BAD.g);

console.log(whitelist, JSON.stringify(BAD, whitelist));

function iterate(obj){
    for(var key in obj){
        whitelist.push(key);
        if(typeof obj[key] === 'object'){
            return iterate(obj[key]);
        }
    }
}
Answer from Dom on Stack Overflow
🌐
MDN Web Docs
developer.mozilla.org › en-US › docs › Web › JavaScript › Reference › Global_Objects › JSON › stringify
JSON.stringify() - JavaScript | MDN
The JSON.stringify() static method converts a JavaScript 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.
Top answer
1 of 3
17

JSON replacer is recursive. This then means it uses the same array for all objects it comes across. In other words, it uses the same values to map BAD.g's value. Since, Bad.g's value does not have any keys matching the ones you provided, nothing will get mapped properly. This means we have to add "2" to your array. Now "2" also has an object with different keys. We have already accounted for "b", so now we just need to add "w" to your array.

When providing an array to the replacer, best to think of the array as a list of all the keys you want mapped.

DEMO: http://jsfiddle.net/dirtyd77/whv7x6xc/4/

console.log(JSON.stringify(BAD, ['a', 'b', 'c', 'd', 'e', 'g', '2', 'w']));

Hope this helps and let me know if you have any questions.


Here is also a snippet from the documentation,

If you return any other object, the object is recursively stringified into the JSON string, calling the replacer function on each property, unless the object is a function, in which case nothing is added to the JSON string.


In the case for dynamic keys, you can always create a function to push to an array and use that array for your whitelist. Here is an example:

DEMO: http://jsfiddle.net/dirtyd77/whv7x6xc/5/

var BAD = {
    "a": "2",
    "b": 1,
    "c": "Nexus",
    "d": "Alligator",
    "e": 5,
    "f": 1431807036,
    "g": {
        "2": {
            "w": 17,
            "b": 5
        }
    }
}

var whitelist = [];

iterate(BAD);

console.log(whitelist, JSON.stringify(BAD, whitelist));

function iterate(obj){
    for(var key in obj){
        // may have to do some checking to ignore any keys you don't care about
        whitelist.push(key);
        // if value is an object, will use this same function to push to whitelist array
        if(typeof obj[key] === 'object'){
            return iterate(obj[key]);
        }
    }
}

You can also just use your existing whitelist and just append keys on your g key (given that isn't dynamic):

DEMO: http://jsfiddle.net/dirtyd77/whv7x6xc/6/

var whitelist = ['a', 'b', 'c', 'd', 'e', 'g'];

iterate(BAD.g);

console.log(whitelist, JSON.stringify(BAD, whitelist));

function iterate(obj){
    for(var key in obj){
        whitelist.push(key);
        if(typeof obj[key] === 'object'){
            return iterate(obj[key]);
        }
    }
}
2 of 3
6

The replacer argument is deep, in that it affects the stringification of all properties, even if they're not on the first level. If you add "2" to the array, you'll see that the object is stringified, minus "w", because "w" is not allowlisted by replacer.

JSON.stringify(BAD, ['a', 'b', 'c', 'd', 'e', 'g', '2'])

Consider why you are using replacer. If you are using it to blocklist, instead of allowlist, you might be better served by passing in a function as opposed to an array.

JSON.stringify(BAD, function replacer(key, value) {
  var blocklist = ['b', 'g']
  return blocklist.indexOf(key) === -1 ? value : undefined
})
🌐
pawelgrzybek
pawelgrzybek.com › til-the-power-of-json-stringify-replacer-parameter
TIL — The power of JSON.stringify replacer parameter | pawelgrzybek.com
JSON.stringify() takes a second optional argument that can be a recursive replacer function or an array of white-listed keys to be stringified.
🌐
Dillion's Blog
dillionmegida.com › p › second-argument-in-json-stringify
The second argument in JSON.stringify() - Dillion's Blog
If any value of the object is another object, the replacer method is recursively called on that object. And if any value of the object is a function, a symbol, or undefined, it will be ignored.
🌐
GitHub
gist.github.com › davidfurlong › 463a83a33b70a3b6618e97ec9679e490
JSON.stringify replacer function for having object keys sorted in output (supports deeply nested objects) · GitHub
function getUniqueObjects(arr) { const replacer = (key, value) => value && typeof value === "object" && !Array.isArray(value) ? Object.keys(value) .sort() .reduce((sorted, key) => { sorted[key] = value[key]; return sorted; }, {}) : value; return arr.filter( (v, i, a) => a.findIndex( (v2) => JSON.stringify(v2, replacer) === JSON.stringify(v, replacer) ) === i ); }
🌐
Reddit
reddit.com › r/javascript › til — the power of json.stringify replacer parameter
r/javascript on Reddit: TIL — The power of JSON.stringify replacer parameter
October 12, 2019 - In JSON.parse there is also a "reviver" parameter. ... const myObject = { set: new Set([1, 2, 3, 4]) }; const replacer = (key, value) => { if (value instanceof Set) { return { __type: "Set", __value: Array.from(value) }; } return value; } const stringified = JSON.stringify(myObject, replacer); const reviver = (key, value) => { if (value && typeof value === "object") { const type = value.__type; switch (type) { case "Set": { return new Set(value.__value); } default: } } return value; }; const myObject2 = JSON.parse(stringified, reviver); console.log(myObject2);
🌐
Bennadel
bennadel.com › blog › 3278-using-json-stringify-replacer-function-to-recursively-serialize-and-sanitize-log-data.htm
Using JSON.stringify() Replacer Function To Recursively Serialize And Sanitize Log Data
April 21, 2020 - Ben Nadel demonstrates how the JSON.stringify() "replacer" function can be used to recursively serialize and sanitize log data. This is incredibly helpful for nested errors and log items that may cont
🌐
Nocommandline
nocommandline.com › blog › json-stringify-replacer-parameter-buffer-and-uint8array
JSON.stringify(), Replacer Parameter, Buffer and Uint8Array
January 29, 2023 - // This example was taken from - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#using_an_array_as_replacer const foo = { foundation: "Mozilla", model: "box", week: 45, transport: "car", month: 7, }; // Keep only "week" and "month" properties const stringified = JSON.stringify(foo, ["week", "month"]); console.log(stringified); // stringified will give {"week":45,"month":7}
Find elsewhere
🌐
W3Schools
w3schools.com › jsref › jsref_stringify.asp
JavaScript JSON stringify() Method
JSON.stringify(obj, replacer, space) Using the replacer function: /*replace the value of "city" to upper case:*/ var obj = { "name":"John", "age":"39", "city":"New York"}; var text = JSON.stringify(obj, function (key, value) { if (key == "city") { return value.toUpperCase(); } else { return value; } }); Try it Yourself » ·
🌐
RestfulAPI
restfulapi.net › home › json › json stringify()
JSON stringify()
November 3, 2023 - JSON.stringify() can optionally use a replacer function to replace values using custom logic.
🌐
EyeHunts
tutorial.eyehunts.com › home › json stringify replacer function | example code
JSON stringify replacer function | Code
May 24, 2023 - const user = { name: 'Danielle', age: 24, city: 'Seattle', admin: false, greet: function greet() { return 'Hello World!' } }; function replacer(key, value) { if (typeof value === 'function') { return value.toString() } return value } const userStringified = JSON.stringify(user, replacer, 3); console.log(userStringified);
🌐
Reddit
reddit.com › r/learnjavascript › json.stringify replacer
r/learnjavascript on Reddit: JSON.stringify replacer
April 25, 2020 -

Hello. I got a little confuse with FIRST argument that return JSON.stringify function replacer.So if I go:

let obj = { 
    a: 5,
    b: 10 
}

JSON.stringify(obj, (key, value) => { 
    if (key !== 'a') {
        return value;
    }
})

It'll fine

"{"b":10}"

But if I change function like this:

JSON.stringify(obj, (key, value) => {
    if (key === 'a') {
        return value;
    }
})

It returns undefined. Why? I think the point is that replacer function in first call get kinda anonymous object where key is <empty string> and value is {a: 5, b: 10}. And this anonymous object is very important for parsing to JSON string. And that's why second version, where passing only key === 'a', doesn't let this anonymous object return. Am I right?

🌐
GitHub
github.com › honojs › hono › issues › 3360
JSON.stringify replacer option · Issue #3360 · honojs/hono
June 13, 2024 - I'm thinking as an initialization option when initializing the Hono app, we can pass a custom stringifier · const app = new Hono({ jsonStringify: jsonStringify }) ... A possible footgun migth be that the replacer function could change the types, but so could the normal JSON.stringify, e.g.
Published   Sep 02, 2024
🌐
freeCodeCamp
freecodecamp.org › news › why-is-the-second-argument-in-json-stringify-usually-undefined
Why is the Second Argument in JSON.stringify() usually null?
March 29, 2023 - The replacer argument can either be a function that is called on every property in the object, or an array that contains keys that should exist in the final output. Using a callback function as a replacer in JSON.stringify, you can loop through ...
🌐
MDN
mdn2.netlify.app › en-us › docs › web › javascript › reference › global_objects › json › stringify
JSON.stringify() - JavaScript | MDN
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.
🌐
Joe Attardi
joeattardi.dev › customizing-jsonparse-and-jsonstringify
Customizing `JSON.parse` and `JSON.stringify`
February 15, 2025 - By the time it is called with the key/value pairs, the stringification of these properties has already been done. However, the original object can still be accessed via the this context (as long as it's not an arrow function!). function replacer(key, value) { if (key === 'lastLogin') { // value is already a string here, but we can access the // original property return this.lastLogin.getTime(); } return value; } const json = JSON.stringify(user, replacer);
🌐
ITNEXT
itnext.io › json-stringify-with-replacer-performance-loss-5c09ed83fa93
JSON stringify with replacer, performance loss? | by Zsolt Deak | ITNEXT
September 7, 2025 - JSON stringify with replacer, performance loss? Logging in Node servers. If you are not a Member, read the free version Node — for the most part — is single-threaded. As such, hogging the (main) …
Top answer
1 of 2
10

Its quite old but just to complete it.

According to this Q/A and the MDN JSON.stringify article, the replacer is called with instance of the object in which the key was found so no need to change prototype or do another tricks:

function log(what) {
   what = what || "";
   document.getElementById("out").innerText += what + "\n";
}

function replacer(key, value) {
   console.log(this);
   log("Key: '" + key + "' = '" + value + "'");
   log("this = " + this);
   log("this[key] = " + this[key]);
   log("this[key] instanceof Date = " + (this[key] instanceof Date));
   log("this instanceof Date = " + (this[key] instanceof Date));
   
   if (this[key] instanceof Date) {
      return "This was a date: " + this[key].getTime();
   }
   
   return value;
}

var obj = {
   d: new Date()
};

var result;
result = JSON.stringify(new Date(), replacer);
log();
log(result);
log();
result = JSON.stringify(obj, replacer);
log();
log(result);
<pre id="out"></pre>

2 of 2
4

Perhaps you could do your formatting before passing the object to JSON, but otherwise here is a possibility:

JSON uses an objects toJSON method before calling the replacer.

So, before calling stringify store the toJSON method and then restore it afterwards.

var object = {
        date: new Date()
    },
    storeToJSON = Date.prototype.toJSON;

delete Date.prototype.toJSON;

JSON.stringify(object, function (key, value) {
    console.log('---');
    console.log('key:', key);
    console.log('value:', value);
    console.log('value instanceof Date:', value instanceof Date);

    return value;
});

Date.prototype.toJSON = storeToJSON;

On jsFiddle

🌐
Execute Program
executeprogram.com › courses › modern-javascript › lessons › customizing-json-serialization
Modern JavaScript: Customizing JSON Serialization
Learn programming languages like TypeScript, Python, JavaScript, SQL, and regular expressions. Interactive with real code examples.