Why are two different keys overriding each other in an object?

Objects can only have strings (or symbols) as their keys. If you try to use a non-string, it gets converted to a string. So when you set c[a] to be 1, a is an object which means it needs to be converted to a string. So you end up setting c["[object Object]"] to be one. Then when you set c[b], you do the same thing, again converting to "[object Object]" and thus overriding the value that's already there.

Try logging out c to see this:

const a = {key:true}
const b = {key:false}
const c = {[a]:'1',[b]:'2'}
console.log(c);

It's unusual to need to use objects as keys, but if you need it, you can use Maps instead of objects

const a = {key:true}
const b = {key:false}
const c = new Map();
c.set(a, '1');
c.set(b, '2');
console.log(c.get(a));
console.log(c.get(b));


Why am I wrong and how can I fix it?

Object property names are converted to strings (if they are not strings or symbols). Object values by default serialize to [object Object], so to JavaScript both values are identical:

const a = {key:true}
const b = {key:false}

console.log('a', a.toString());
console.log('b', b.toString());


1. You can implement your own toString method to serialize the object to distinctive strings:

function toString() {
  return this.key.toString();
}

const a = {key:true, toString}
const b = {key:false, toString}
const c = {[a]:'1',[b]:'2'}
console.log(c[a],c[b]) 

But that doesn't let you recover the original value that was used as key (you could use a JSON representation of the object as key, which you could convert back to an object, but that only works if the "key object" only contains values that can be expressed in JSON).


2. You can use a Map instead of an object, which allows for arbitrary values as keys:

const a = {key:true}
const b = {key:false}
const c = new Map([[a, '1'], [b, '2']]);
console.log(c.get(a),c.get(b)) 

Note that Maps use object identity to look up values, so c.get({key: false}) will not work.


Which way to go really depends on what you need.


You may have a look to c, where you see the result of a.toString()

const a = { key: true }
const b = { key: false }
const c = { [a]: '1', [b]: '2' }

console.log(c);
console.log(c[a], c[b]);

For overcoming this problem, you could take a JSON string

const a = { key: true }
const b = { key: false }
const c = { [JSON.stringify(a)]: '1', [JSON.stringify(b)]: '2' }

console.log(c);
console.log(c[JSON.stringify(a)], c[JSON.stringify(b)]);

Especial for objects as keys, you could use WeakMap:

const a = { key: true }
const b = { key: false }
const c = new WeakMap([[a, '1'], [b, '2']]);

console.log(c.get(a), c.get(b));

Tags:

Javascript