I have a situation where I have an object with a lot of Date instances in it. The object is then transformed into JSON, and returned:
router.post('/', function () {
// Some code that returns the object
res.status(200).json(object);
});
I need to change how all of the Date objects are converted to JSON, so I was thinking of doing this:
router.post('/', function() {
var originalToJSON = Date.prototype.toJSON;
Date.prototype.toJSON = function() {
return moment(this).format(...); // some formatting function
}
res.status(200).json(object);
Date.prototype.toJSON = originalToJSON;
});
I realize this is a terrible practice, but I'm curious what the implications are. Since I'm restoring Date.prototype.toJSON to it's original state right after the object is converted to JSON, is it possible that requests that come in meanwhile res.status(200).json(object) is running, and get the overwritten Date.prototype.toJSON?
It shouldn't be a problem that some other parts of your code will use the changed JSON method because the code runs to completion and doesn't yield or await between those two changes of JSON methods, but there is a risk that your code wouldn't use your changed method - it depends really on the implementation of res.json() and while it may work now, it may stop working in the future if the internal implementation of Express changes - and relying on it not changing is a leaky abstraction with a risk of breakage in the future.
You can do few other things here:
replacer parameter of JSON.stringify to your advantageFor number 3, see: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify
The replacer parameter can be either a function or an array. As a function, it takes two parameters, the key and the value being stringified. The object in which the key was found is provided as the replacer's this parameter. Initially it gets called with an empty key representing the object being stringified, and it then gets called for each property on the object or array being stringified. [...] If you return a String, that string is used as the property's value when adding it to the JSON string.
In your particular case the replacer could just return the dates formatted however you want and return everything else unchanged. The replacer parameter of JSON.stringify() is created specifically for cases like that.
In that precise case, everything is synchrnous, so will be executed in one go. As such, it should be safe to do that.
However, messing with prototype is often a bad idea, especially when there is much simpler solutions to your problem:
function toJSON(input) {
if(typeof input === 'date') {
return moment(input).format();
} else if(typeof input === 'object') {
let o = {};
Object.keys(input).map((key) => {
o[key] = toJSON(input[key]);
});
return o;
} else {
return input;
}
}
router.post('/', function() {
var originalToJSON = Date.prototype.toJSON;
Date.prototype.toJSON = function() {
return moment(this).format(...); // some formatting function
}
res.status(200).json(toJSON(object));
Date.prototype.toJSON = originalToJSON;
});