78

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);
alert(json);

What is the correct way of JSON'ing this array?

Octopus
  • 8,075
  • 5
  • 46
  • 66
Sherlock
  • 7,525
  • 6
  • 38
  • 79

6 Answers6

134

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);
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • 2
    But if I use an Object, it doesn't have the array prototypes like splice. – Michael Aug 15 '20 at 22:45
  • 1
    @Michael — Maybe you should ask a new question in which you explain your problem that for some reason requires that you splice on something with named properties that you need to stringify to JSON. – Quentin Aug 15 '20 at 23:10
12

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"]}"
Community
  • 1
  • 1
Adrien
  • 365
  • 3
  • 9
  • I had some issues with a site that overwrite Date, so when I use the Date.toJSON fails I so I added: Date.prototype.toJSON = Date.prototype.toISOString; – Adrien Sep 16 '14 at 13:05
6

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);
    };
})();
Community
  • 1
  • 1
JVE999
  • 3,327
  • 10
  • 54
  • 89
  • this is a nice start, but it's making some assumptions, for instance, that the array doesn' t have any indexed values. – Michael Aug 15 '20 at 22:47
2

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;
});
vkarpov15
  • 3,614
  • 24
  • 21
1

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.

-7

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});