36

Javascript objects can be used as maps. The following all is valid code:

var x = {};
x.a = 1;
x['b'] = 2; // the same as x.b = 2;
x[3] = 3; // x.3 won't work, but this syntax works fine. Also, x[3] == x['3'].
x['What, this works too?!?!?'] = 'Yup, it does!';

But today I tested another case which... seems to work, but raises some warning flags in my head because it looks... wrong:

x[null] = 42;

Now, it would be extremely cool if this worked as expected (I won't have to rewrite a bunch of code then), but can I rely on it? Or maybe this is just some undocumented behavior which just happens to work in all modern browsers but might as well cease working on the next release of Google Chrome?

Vilx-
  • 104,512
  • 87
  • 279
  • 422
  • 3
    The indexing argument is converted to a string before any operations are performed. Try `console.log(x["null"])` after your last assignment. You noticed that when dealing with the `3` subscript. – Alexander Pavlov Mar 13 '12 at 16:20
  • 1
    Also fun: `x[x]=1`, which is technically indexed as `x['[object Object]']` and the same value as `x[{}]`. And if you hate other people: `x[x[x]]=2`. – Deestan Mar 13 '12 at 16:21

5 Answers5

37

Anything between the property brackets is converted to a string. null becomes "null", which is a valid property.

Rob W
  • 341,306
  • 83
  • 791
  • 678
  • 1
    @Vilx- PS. `var d={};d[{}]=1;JSON.stringify(d)` shows `{"[object Object]":""}` and `var x={};x[{toString:function(){return 123}}]=1; Object.keys(x)` contains `123`. – Rob W Mar 13 '12 at 16:25
  • Also, see http://stackoverflow.com/a/10362142 for an indepth discussion on why null has a string representation. – bebbi Sep 18 '15 at 12:33
  • Everything is converted to a string, except symbols, right? – David Callanan Nov 21 '18 at 16:34
3

It's valid ECMAScript 5, but you may run into problems in some versions of Internet Explorer.

This is all fine:

x = {};
x[null] = 42;
x[null];
// 42

x = {"null": 42};
x[null];
// 42

However, IE8 doesn't accept the following with reserved words such as null:

x.null
// Error: Expected identifier

x = {null: 42}
// Expected identifier, string or number

(Both of the above work in Chrome, even with "use strict" enabled.)

Ian Mackinnon
  • 13,381
  • 13
  • 51
  • 67
1

If your environment supports ES6 and you need to be able to store a value for null as well as any arbitrary string then you can use a Map.

const a = new Map();

a.set(null, 'foo')
a.set('null', 'bar')

// Map { null => 'foo', 'null' => 'bar' }
Crazometer
  • 457
  • 7
  • 12
1

I cannot leave comments so I created an answer...

While Rob W is correct his answer is a little misleading. The item between the square brackets is converted to a string using ToString(). So, a[null] only equals a['null'] because ToString( null ) == 'null'

take for instance

var a = 1;
var x = {}

x[a] = 20;
x['1'] = 30; -- this is exactly the same as the previous line and now x[a] == 30
Charlie
  • 931
  • 1
  • 6
  • 10
0
x['null'] = 42;

I would strongly dis-recommend that, though, to avoid confusion.

Property names are strings. Every string will work, even ones that represent reserved identifiers.

Everything that's not a string will be converted into a string (by calling the object's toString() method):

a = ['FOO'];   // an array
o = {};        // an object
o[a] = 'foo';  // using a as the property name

// o now is:
{
  FOO: 'foo'
}
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • In my case the indexes are numeric, except for the one special "null" index. I don't think it will cause a confusion. – Vilx- Mar 13 '12 at 16:33
  • Well, it smells, like re-defining `undefined`. Numeric indexes are converted to stings, too. – Tomalak Mar 13 '12 at 17:07
  • Hm? I'm not redefining anything. It's like... there's a bunch of data objects and I need to group them by one of their properties (that property actually being a numerical ID in the DB). Today I came across the situation where I also needed to incorporate data from another data source, but the data objects coming from that source don't include an ID for this property. They don't belong to any of the groups that the original items make, but rather... belong to them all, sort of. So I need a special value to mark those objects, and null seems like a nice fit. – Vilx- Mar 14 '12 at 08:48
  • I guess I could use any other value (like -1), but null is already used as the "special" value it most languages, and the DB, so it really seems appropriate to me here. If you wish I can give more details, as maybe this story is a bit too abstract. :P – Vilx- Mar 14 '12 at 08:49
  • @Vilx No, I understand what you mean. It's not that you *musn't* do it, as long as you are concious about how things work. But the very fact that you came here to ask kind of proves my point that it is a little confusing. – Tomalak Mar 14 '12 at 09:01
  • I guess you have a point there. Still. I can't imagine that adding explicit checks everywhere would improve the understandability of code. Well... let's just hope that the next guy who has to maintain this isn't an axe-wielding psychopath! XD – Vilx- Mar 14 '12 at 10:13