Reputation: 7597
I must be missing something here, but the following code (Fiddle) returns an empty string:
var test = new Array();
test['a'] = 'test';
test['b'] = 'test b';
var json = JSON.stringify(test);
console.log(json);
What is the correct way of stringifying this array?
Upvotes: 80
Views: 177474
Reputation: 165
Yes, JavaScript arrays are not associative like php-arrays, they are designed to hold data with numeric indexes. But I understand what you want. JavaScript arrays can contain both object properties (like "string indexes") and numbers in strings (like "number indexes"). You can stringify/serialize it only to plain JavaScript object {"key1": value1, "key2": value2, ...}
.
E.g. you want stringify an array a
, but avoid null/undefined in output (for clarity question is extended):
a = []; // new Array();
a[0] = "UK";
a[1] = 7;
a["5"] = 8;
a["32"] = 77;
a[7] = 0;
a["8"] = NaN;
a[9] = undefined;
a["10"] = null;
a[11] = {};
a["19"] = false;
a[20] = true;
a['A'] = 'test';
a['B'] = 'test B';
a.push('wonderland');
a.push(98);
a[4294967294] = 42;
delete a[4294967294];
(4294967295) ['UK', 7, empty × 3, 8, empty, 0, NaN, undefined, null, {…}, empty × 7, false, true, empty × 11, 77, 'wonderland', 98, empty × 4294967260, A: 'test', B: 'test B']
a.length
4294967295
So even JSON.stringify(a)
could be possible, it will be finished with many nulls (and without 'A', 'B')...
'["UK",7,null,null,null,8,null,0,null,null,null,{},null,null,null,null,null,null,null,false,true,null,null,null,null,null,null,null,null,null,null,null,77,"wonderland",98,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,...
We can fix it with Object.assign!
function replacer (key, value) {
return (!!value || value === false || value === '' || typeof value === 'number') ? value : undefined;
}
JSON.stringify(Object.assign({}, a), replacer)
Or even simpler:
JSON.stringify(Object.assign({}, a))
'{"0":"UK","1":7,"5":8,"7":0,"8":null,"10":null,"11":{},"19":false,"20":true,"32":77,"33":"wonderland","34":98,"A":"test","B":"test B"}'
Back conversion to array is harder:
jsonObj = JSON.stringify(Object.assign({}, a));
aObj = JSON.parse(jsonObj)
b = []
Object.entries(aObj).forEach(entry => b[entry[0]] = entry[1])
console.log(b)
(35) ['UK', 7, empty × 3, 8, empty, 0, null, empty, null, {…}, empty × 7, false, true, empty × 11, 77, 'wonderland', 98, A: 'test', B: 'test B']
P. S. 1: You can also see, that we filtered null/undefined for extremely long source array (sparse array) a
, which was impossible with array.filter.
P. S. 2: But for our specific task, we can not use JSON.stringify(Object.assign([], a))
, because we do not want to miss a['A'] = 'test'; a['B'] = 'test B'
.
P. S. 3: To avoid using such unintuitive things, you must use Plain Object {}
or better Map
.
Upvotes: 1
Reputation: 3872
Another approach is the JSON.stringify()
replacer function param. You can pass a 2nd arg to JSON.stringify()
that has special handling for empty arrays as shown below.
const arr = new Array();
arr.answer = 42;
// {"hello":"world","arr":{"answer":42}}
JSON.stringify({ hello: 'world', arr }, function replacer(key, value) {
if (Array.isArray(value) && value.length === 0) {
return { ...value }; // Converts empty array with string properties into a POJO
}
return value;
});
Upvotes: 3
Reputation: 943579
JavaScript arrays are designed to hold data with numeric indexes. You can add named properties to them because an array is a type of object (and this can be useful when you want to store metadata about an array which holds normal, ordered, numerically indexed data), but that isn't what they are designed for.
The JSON array data type cannot have named keys on an array.
When you pass a JavaScript array to JSON.stringify
the named properties will be ignored.
If you want named properties, use an Object, not an Array.
const test = {}; // Object
test.a = 'test';
test.b = []; // Array
test.b.push('item');
test.b.push('item2');
test.b.push('item3');
test.b.item4 = "A value"; // Ignored by JSON.stringify
const json = JSON.stringify(test);
console.log(json);
Upvotes: 138
Reputation: 375
Nice explanation and example above. I found this (JSON.stringify() array bizarreness with Prototype.js) to complete the answer. Some sites implements its own toJSON with JSONFilters, so delete it.
if(window.Prototype) {
delete Object.prototype.toJSON;
delete Array.prototype.toJSON;
delete Hash.prototype.toJSON;
delete String.prototype.toJSON;
}
it works fine and the output of the test:
console.log(json);
Result:
"{"a":"test","b":["item","item2","item3"]}"
Upvotes: 13
Reputation:
Alternatively you can use like this
var test = new Array();
test[0]={};
test[0]['a'] = 'test';
test[1]={};
test[1]['b'] = 'test b';
var json = JSON.stringify(test);
alert(json);
Like this you JSON-ing a array.
Upvotes: 1
Reputation: 15
Json has to have key-value pairs. Tho you can still have an array as the value part. Thus add a "key" of your chousing:
var json = JSON.stringify({whatver: test});
Upvotes: -7
Reputation: 3517
I posted a fix for this here
You can use this function to modify JSON.stringify
to encode arrays
, just post it near the beginning of your script (check the link above for more detail):
// Upgrade for JSON.stringify, updated to allow arrays
(function(){
// Convert array to object
var convArrToObj = function(array){
var thisEleObj = new Object();
if(typeof array == "object"){
for(var i in array){
var thisEle = convArrToObj(array[i]);
thisEleObj[i] = thisEle;
}
}else {
thisEleObj = array;
}
return thisEleObj;
};
var oldJSONStringify = JSON.stringify;
JSON.stringify = function(input){
if(oldJSONStringify(input) == '[]')
return oldJSONStringify(convArrToObj(input));
else
return oldJSONStringify(input);
};
})();
Upvotes: 6