I was recently editing some code that another developer had written when I noticed some strange behavior.
Note: in this post I use the terms “object properties”, “expando properties”, and “dictionary values” interchangeably. In JavaScript, you can add named values to an object in a few ways but each is mostly interchangeable. For example, these do the same thing:
x["a"] = 1;
x.a = 1;
I needed to take an existing JavaScript object and stringify it and send the JSON to the server. That’s fairly straightforward, but
Technorati Tags:
JavaScript
I quickly realized that the JSON I was receiving was missing a bunch of values that I was expecting.
It turned out the source of the error was in the variable declaration of the object I was stringifying. The variable was declared as:
var a = new Array();
But, when values were added to the variable they were added using the dictionary syntax such as:
a[“key”] = 3;
Even though the variable is declared wrong, it appeared to work fine everywhere. That is, until I tried to stringify it.
A quick note, if you don’t know what stringify is then take a look over at json.org. The short answer is that stringify() is a method on the JSON object that lets you turn a JavaScript object into its JSON representation.
The problem seems to be that when stringify() encounters an array object, while it does serialize the indexed elements it doesn’t serialize any expando properties.
This makes sense if you think about it. JSON has a representation for objects with properties and for arrays, but the array notation has no way of also including properties.
The example below demonstrates that no dictionary values that were added to the array are serialized when the array is stringified, but in the object the properties are output. Note, I used the shorthand notation for object {} and array [] in the example below.
Example Code:
<label for="out_a1">A property read: </label><span id="out_a1"></span><br />
<label for="out_a2">A strinify: </label><span id="out_a2"></span><br />
<label for="out_b1">B property read: </label><span id="out_b1"></span><br />
<label for="out_b2">B strinify: </label><span id="out_b2"></span><br />
<script type="text/javascript">
var a = {};
var b = [];
a["alpha"] = "alpha";
b["beta"] = "beta";
var out_a1 = document.getElementById("out_a1");
out_a1.innerHTML = a["alpha"];
var out_a2 = document.getElementById("out_a2");
out_a2.innerHTML = JSON.stringify(a);
var out_b1 = document.getElementById("out_b1");
out_b1.innerHTML = b["beta"];
var out_b2 = document.getElementById("out_b2");
out_b2.innerHTML = JSON.stringify(b);
</script>
Example Output:
A property read: alpha
A strinify: {"alpha":"alpha"}
B property read: beta
B strinify: []
The solution in my problem was to change the object declaration from array to object and everything worked fine.
I could have run into a problem if the object was being accessed as both an array and an object. You can do this. I tried it out in a couple of browsers (IE8 and Chrome) and it worked. If that had been the case, then I would have had to refactor the code because there would be not way to output both the array elements and the object properties in one JSON element.