Why Do I See Individual Characters Instead of Objects When I Loop Over JSON?
You’re receiving JSON data from a server call. But once you try to parse it in client-side code, you see something weird and unexpected. Maybe you know the data was sent as an array, but after parsing, when you console log each item, it’s outputting individual characters instead of the parsed objects you expect.
What gives?
Let’s first clarify some terms.
There are two Javscript methods that are used a lot with JSON:
JSON.stringify(someObject);
JSON.parse(someJSON);
These do opposite things.
JSON.stringify
converts something to JSON – it takes in a Javascript object and returns the resulting JSON string. JSON is just formatted text, stored as a string.
JSON.parse
converts something from JSON – it takes a string that must already be in a JSON format and returns a resulting Javascript object.
These methods would probably be a lot clearer if they were called something like:
JSON.toJSON
instead ofJSON.stringify
JSON.fromJSON
instead ofJSON.parse
…but, alas, it is what it is.
So if you stringify something, then you parse the result of that, you’ll end up with the exact same thing you started out with.
For example:
const original = { hello: "world" };
const jsonVersion = JSON.stringify(original);
// is the string '{ hello: "world" }'
const parsedVersion = JSON.parse(jsonVersion);
// is an object that looks exactly
// like the original: { hello: "world" }
If you find yourself calling JSON.stringify on data coming from a server, this is most likely unnecessary, because it should already be in JSON format. The server most likely did its own version of JSON.stringify
before it sent the response to the client. What you want, instead, is to get it out of JSON and into a Javascript object, which is what JSON.parse
does.
If your data is already in JSON format, then calling JSON.stringify
on it will cause problems.
The reason is that JSON.stringify
is dumb and doesn’t know you’re passing it JSON. When passed a string, JSON.stringify
simply takes whatever you gave it and wraps it in double quotes.
const jsonFromServer = '[ "world", "planet", "moon" ]';
const stringifiedJson = JSON.stringify(jsonFromServer);
// is the string: '"[ \"world\", \"planet\", \"moon\" ]"'
See how the value of stringifiedJson
is now a string, that contains another quoted string, which happens to be JSON?
If you then try to parse that string, you get the original string back, instead of the array you were hoping for:
const jsonFromServer = '[ "world", "planet", "moon" ]';
const stringifiedJson = JSON.stringify(jsonFromServer);
// is the string: '"[ \"world\", \"planet\", \"moon\" ]"'
const parsedJson = JSON.parse(stringifiedJson);
// is the string: '[ "world", "planet", "moon" ]'
If you then try to iterate over that string… well, Javascript allows you to loop over strings using the same methods that you’d use for arrays… except instead of iterating over array items, it’s iterating over individual characters.
const jsonFromServer = '[ "world", "planet", "moon" ]';
const stringifiedJson = JSON.stringify(jsonFromServer);
// is the string: '"[ \"world\", \"planet\", \"moon\" ]"'
const parsedJson = JSON.parse(stringifiedJson);
// is the string: '[ "world", "planet", "moon" ]'
for (var i = 0; i < parsedJson.length; i++) {
console.log(parsedJson[i]);
}
/* Result:
'['
' '
'"'
'w'
'o'
'r'
'l'
'd'
'"'
','
etc...
*/
Same thing goes for Object.keys
:
const jsonFromServer = '[ "world", "planet", "moon" ]';
const stringifiedJson = JSON.stringify(jsonFromServer);
// is the string: '"[ \"world\", \"planet\", \"moon\" ]"'
const parsedJson = JSON.parse(stringifiedJson);
// is the string: '[ "world", "planet", "moon" ]'
Object.keys(parsedJson).forEach(key => {
console.log(parsedJson[key]);
});
/* Result:
'['
' '
'"'
'w'
'o'
'r'
'l'
'd'
'"'
','
etc...
*/
That’s why you’re seeing individual characters in the console, instead of the objects you expect.
The solution is likely very simple: if you are calling both JSON.stringify()
and JSON.parse()
on the data coming from the server, try removing the JSON.stringify()
call. You should be able to simply call JSON.parse()
directly on the data you received from the server.
If you’re still seeing individual characters, you may still have some lingering JSON.stringify()
calls somewhere – or even an equivalent “to JSON” step happening too many times, somewhere on your server.