Okay so I am trying to replicate JSON.stringify. Currently I am getting this error. Unfortunately this error is not very helpful because the message is cut short before it actually gets to what the problem is so I am quite stuck. Can anyone tell me what is wrong with my object code? I am currently commenting out the recusive code for nested arrays/objects as the tests for that are separate.
Here is the code (only the code relevant to arrays and objects):
if (Array.isArray(input)) {
var toJSON = '[';
var key = 0;
function toString() {
if (input.length === 0) {
return '[]';
}
if (key < input.length) {
// if (Array.isArray(input[key]) || typeof input[key] === 'object') {
// toJSON += stringifier(input[key]);
// }
if (input[key] === null || typeof input[key] === 'function' || input[key] === undefined) {
toJSON += 'null';
}
if (typeof input[key] === 'number' || typeof input[key] === 'boolean') {
toJSON += `${input[key]}`;
}
if (typeof input[key] === 'string') {
toJSON += `"${input[key]}"`;
}
key++;
if (key < input.length) {
toJSON += ',';
}
toString();
}
}
toString();
return toJSON + ']';
}
if (typeof input === 'object') {
if (Object.keys(input).length === 0) {
return '{}';
}
var toJSON = '{';
for (var key in input) {
toJSON += `"${key}":`;
// if (Array.isArray(input[key]) || typeof input[key] === 'object') {
// toJSON += stringifier(input[key]);
// }
if (input[key] === null || input[key] === undefined || typeof input[key] === 'function') {
toJSON += `null`;
} else if (typeof input[key] === 'number') {
toJSON += `${input[key]}`;
} else if (typeof input[key] === 'string') {
toJSON += `"${input[key]}"`;
}
if (key != Object.keys(input)[Object.keys(input).length - 1]) {
toJSON += ',';
}
}
return toJSON + '}';
}
Now if I uncomment the recursive code, it breaks the array code that is currently working and I get this:
2
Answers
There are several issues with your code
in your object serialization (and seemingly also in your testcases) you forgot to handle
boolean
s. Ie, you will output the property’s name, but not its value. Thuswill produce an output of
{"a": }
which is obviously wrongYou are serializing
undefined
tonull
. That’s not standard behaviour. Not sure whether your project is defined that way, butwill produce
{}
whereas your code produces{"a": null}
In both of your code parts (ie for arrays and for objects) you are checking
in the very beginning. The problem with that is, that
typeof null === "object"
ie, your recursive call will get an input ofnull
which probably leads to erroneous results.I’d suggest to handle all primitives (
number
,string
,boolean
,undefined
,null
) first. And only if none of them applies, treat it as object or array …For adding the comma, I’d suggest a different approach. Instead of checking if there is an additional element/property to handle and add the comma at the end of the current iteration’s body, move this code to the beginning of the iteration and check if the current iteration is the very first iteration.
You may need special treat for some special objects like
Date
orError
, because handling them like standard objects may lead to undesired results. Ie for instanceproduces an ISO date string like
"2023-07-06T13:08:29.460Z"
And just as a general remark: It would probably be better, to just handle the
Array
andobject
specific parts separately and handle the serialization of primitive values in a single point. Ie currently you have to duplicate the code for serializingnumber
,string
orboolean
which reduces maintainability and is (as your case shows) error prone. I’d suggest something like the following.It’s quick and dirty. There may be some issues with special cases, but you get the idea. One issue with this code is, it doesn’t properly handle strings containing double quotes. Ie something like
serialize({a:'a " string'})
leads to an erroneous JSON string …JavaScript datum are represented with objects (compound) and primitive data elements which can be nested to any conceivable depth. A recursive procedure is best suited to match the recursive structure of the input data.
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignments, and other side effects. In the code below, we perform a simple type analysis of the input
t
, and immediately return the computed JSON representation –See this Q&A for the original implementation.