Saturday, July 14, 2012

Javascript maps

This will be a short blog post that shows my error in understanding what Javascript maps or objects are. I don't mean Google Maps, I mean dynamic objects that have properties that can be accessed via a key, not an index. Let's me exemplify:
var obj={
  property3: new Date()
obj["property 4"]="value 4";
obj.property5=new MyCustomObject();
obj[6]='value 6';
console.log(obj['property 4']);
In this example, obj is an instance of object that had three properties and others are added. First the declaration notation is JSON like, then any object can be assigned to a property via two notations: the '.'(dot) and the square brackets. Note that the value of 'property 4' and of '6' can only be accessed via square brackets, there is no dot notation to escape that space and obj.6 is invalid.

Now, the gotcha is that, coming from the C# world, I've immediately associated this with a Hashtable class: something that can have any object as key and any object as value, but instead, a map is more like a Dictionary<string,object>.

Let me show you why that may be confusing. This is perfectly usable:
obj[new Date()]=true;
In this example I've used a Date object as a key. Or have I? In Javascript any object can be turned into a string with the toString() function. In fact, our Javascript map uses a key much like 'Sat Jul 14 2012 00:07:00 GMT+0300 (GTB Daylight Time)'. The translations from one type to another are seamless (and can generate quite a bit of righteous anger, too).

My point is that you can also use something like
obj[new MyObject()]=true;
only to see it blow in your face. The key will most likely be '[Object object]'. Not at all what was expected.

So remember: javascript properties can be any string, no matter how strange, but not other types. obj[6] will return the value you have set in obj[6] because in both cases that 6 is first turned into a string '6' and then used. It has nothing to do with the '6th value' or '6th property'. Those are arrays. The same for a Date or some custom object that has a toString() function that returns something unique for that object. I wouldn't use that, though, as you would probably want to use objects as keys and compare them by reference, not string value.