Reputation: 79850
I was trying to stringify an array-like object that was declared as an array object and found that JSON.stringify wasn't processing correctly array-like object when it is defined as an array object.
See below for more clarity, --> jsFiddle
var simpleArray = []; //note that it is defined as Array Object
alert(typeof simpleArray); // returns object -> Array Object
simpleArray ['test1'] = 'test 1';
simpleArray ['test2'] = 'test 2';
alert(JSON.stringify(simpleArray)); //returns []
It worked fine and returned me {"test1":"test 1","test2":"test 2"}
when I changed
var simpleArray = [];
to var simpleArray = {};
.
Can someone shed some light or some reference where I can read more?
Edit:
Question: When typeof simpleArray = []
and simpleArray = {}
returned object, why JSON.stringify wasn't able to return {"test1":"test 1","test2":"test 2"}
in both cases?
Upvotes: 6
Views: 3359
Reputation: 14980
The differences between Array
instances and other objects are specified in the ECMAScript Language Specification, Edition 5.1, section 15.4.
You will find there that while you can use the bracket property accessor syntax with all object references --
objRef[propertyName]
-- Array
instances are special. Only using a parameter value which string representation is that of an unsigned 32-bit integer value less than 232-1 accesses an element of the encapsulated array structure, and write access affects the value of the Array
instance's length
property.
Section 15.12 specifies the JSON
object and its stringify
method accordingly.
Upvotes: 1
Reputation: 57721
Your code is not semantically correct, but because most JavaScript engines are really nice on the programmer they allow these types of mistakes.
A quick test case:
var a = [];
a.b = "c";
console.log(JSON.stringify(a));//yields [], and not {"b":"c"} as you might expect
This might be because of some strictness in JSON.stringify
which still treats a
like an Array
.
I wouldn't worry about it overly much. This is a situation that should not occur in your program because it is an error. JSLint is a popular tool to catch these and many more potential problems in your code.
Upvotes: -1
Reputation:
"Can someone shed some light or some reference where I can read more?"
When you're dealing with JSON
data, you can refer to json.org to read about the requirements of the specification.
In JSON
, an Array
is an order list of values separated by ,
.
So the JSON.stringify()
is simply ignoring anything that couldn't be represented as a simple ordered list.
So if you do...
var simpleArray = [];
simpleArray.foo = 'bar';
...you're still giving an Array, so it is expecting only numeric indices, and ignoring anything else.
Because JSON
is language independent, the methods for working with JSON
need to make a decision about which language structure is the best fit for each JSON
structure.
So JSON has the following structures...
{} // object
[] // array
You should note that though the look very similar to JavaScript
objects and arrays, they're not strictly the same.
Any JavaScript
structures used to create JSON
structures must conform to what the JSON
structures will allow. This is why the non-numeric properties are removed excluded.
While JavaScript
doesn't mind them, JSON
won't tolerate them.
Upvotes: 2
Reputation: 285077
You don't want an array. When you want an "associative array" in JavaScript, you really want an object, {}
.
You can distinguish them with instanceof Array
:
[] instanceof Array // true
({}) instanceof Array // false
EDIT: it can process it. It serializes all of the elements of the array. However, to be an element, there must be a numeric key. In this case, there are none.
This is nothing unique to JSON. It's consistent with toSource
and the length
property.
Upvotes: 2
Reputation: 4032
In Javascript, everything is an object, so even Arrays. This is why you get:
>> var l = [1, 2];
>> typeof l
"object"
Arrays are stored the same way as objects. So, in fact, arrays are only hashtable objects. The index you provide when accessing e.g.
>> l[0]
is not interpreted as an offset, but is hashed and then searched for.
So Arrays, are just objects (with some builtin array-methods) and so you can treat them like objects and put a value under a certain key. But only those keys indexed by numbers are used to compute the length.
>> var l = []
>> l.length
0
>> l[5] = 1;
>> l.length
6
>> l
[undefined, undefined, undefined, undefined, undefined, 1]
>> l.hello = "Hello"
>> l.length
6
Read Array - MDN for more information and Associative Arrays considered harmful why you should not do this.
Upvotes: 0
Reputation: 324810
When JSON.stringify
encounters an array, it iterates in a similar way to a for
loop from 0
to simpleArray.length
to find the values. For example:
var a = [];
a[5] = "abc";
alert(JSON.stringify(a)); // alerts [null,null,null,null,null,"abc"]
Therefore setting properties on it will be completely invisible to JSON.
However defining the object with {}
makes JSON treat it as an object, and therefore it loops over the object's properties (excluding inherited properties from the prototype chain). In this manner it can find your test1
and test2
properties, and successfully returns what you expect.
Upvotes: 1
Reputation: 1039498
The difference is the indexes. When you use an array []
the indexes can only be positive integers.
So the following is wrong:
var array = [ ];
array['test1'] = 'test 1';
array['test2'] = 'test 2';
because test1
and test2
are not integers. In order to fix it you need to use integer based indexes:
var array = [ ];
array[0] = 'test 1';
array[1] = 'test 2';
or if you declare a javascript object then the properties can be any strings:
var array = { };
array['test1'] = 'test 1';
array['test2'] = 'test 2';
which is equivalent to:
var array = { };
array.test1 = 'test 1';
array.test2 = 'test 2';
Upvotes: 5