Search code examples
javascriptjsonstringify

Call the replacer *before* the object's toJSON?


Is there a way to get my replacer called before an object's own toJSON transforms it, so that I can work with the original object rather than its JSON-friendly form, without overriding the toJSON on the object or its prototype, pre-processing the object, or writing my own version of JSON.stringify?

For example: Suppose I want to serialize Date instances differently than their normal serialization (which is toISOString). (This question is not specific to Date, this is just an example.) The problem is, my replacer doesn't see the Date object, it sees a string (see snippet below) because Date.prototype.toJSON is called before my replacer.

var obj = {
  d: new Date()
};
snippet.log(getType(obj.d));     // "[object Date]"

var json = JSON.stringify(obj, function(key, value) {
  if (key === "d") {
    snippet.log(getType(value)); // "string" <== Want to see a Date here
  }
  return value;
});

function getType(value) {
  var to = typeof value;
  if (to === "object") {
    to = Object.prototype.toString.call(value);
  }
  return to;
}
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

Is there a way to get the replacer called first? I don't want to override Date.prototype.toJSON, pre-process the object, or write my own JSON.stringify, but I'm not seeing another way.


Solution

  • If I understand you correct this should do the trick, I'm pretty sure this is always the object JSON.stringify is currently iterating over:

    var json = JSON.stringify(obj, function(key, value) {
      if (key === "d") {
        snippet.log(getType(this[key]));
      }
      return value;
    });