var a = new Object;
var b = new Object;
var c = new Object;
c[a] = a;
c[b] = b;
console.log(c[a] === a);
I tested the code above and get false
. If I try console.log(c[a] === b)
, then true
is printed.
Why?
var a = new Object;
var b = new Object;
var c = new Object;
c[a] = a;
c[b] = b;
console.log(c[a] === a);
I tested the code above and get false
. If I try console.log(c[a] === b)
, then true
is printed.
Why?
Share Improve this question edited May 9, 2015 at 5:53 royhowie 11.2k14 gold badges53 silver badges67 bronze badges asked May 9, 2015 at 4:44 LevisLevis 4084 silver badges11 bronze badges 5 |3 Answers
Reset to default 35The problem here has to do with how an Object
's keys are set. From MDN:
Parameters
nameValuePair1, nameValuePair2, ... nameValuePairN
- Pairs of names (strings) and values (any value) where the name is separated from the value by a colon.
value
- Any value.
An object's values can be accessed (via the appropriate key) in three ways:
var o = {};
var key = "fun";
// method 1:
o[key] = "the key will be equal to `key.toString()"
// method 2:
o.key = "the key will be equal to 'key'"
// method 3:
o["key2"] = "the key will be equal to `key2`"
/*
{
"fun" : "the key will be...", // method 1
"key" : "the key will be...", // method 2
"key2": "the key will be..." // method 3
}
*/
When using bracket notation, you need to mind the gap...between the brackets! Objects set their keys and values using the toString
method, unless they're passed a string (then there's no point in toString
). When using the dot notation, they use .key
as the key.
Let's look at your case:
var a = {}
, b = {}
, c = {}
;
c[a] = a;
// `a` is not a string, and we're using brackets, so the key
// will be equal to `key.toString()`:
// a.toString() === "[object Object]"
// Try the following in your console: `{}.toString()`
// Note how this is different from console.log({}), since
// the console exposes your object (that's why the dev console is useful)
// c is now: `{ "[object Object]" : a }`
c[b] = b;
// b is also an object, so `b.toString()` is the same as `a.toString()`
// that means c is now `{ "[object Object]" : b }`
assert c[a] === a
// a.toString() == b.toString() == "[object Object]"
// and we just noted that c was `{ "[object Object]" : b }`
// so of course this is false
assert c[b] === b
// true because c[b] == b;
assert c["[object Object]"] === b;
// also true
assert c.b === b
// false, since `c` has no "b" key (c.b is `undefined`)
Object is not a valid key for JavaScript Object, only strings are
So, when you do this:
c[a] = a;
c[b] = b;
The compiler can not use the a or b as a key for c as in c[a] or c[b].
However, it does not fail, because JavaScript can work around this problem. First it figures out that
- The variable is an object and
- The variable has toString -function
Thus, the JavaScript compiler will call toString() of each of those variables. And by default, the Object.prototype.toString it will return "[object Object]" -string, because the implementation is the default implementation which does that and that value becomes the new key
c["[object Object]"] = a;
c["[object Object]"] = b; // overrides the previous
Which is not what you wanted. The problem is that toString will by default return always the same value, so assigments will always go to the same key.
To demonstrate that toString is actually the problem, you can actually do a horrible cheat to make each object return unique string
// don't do this!!!
(function() {
var id=1;
Object.prototype.toString = function() {
if(!this._id) this._id = id++;
return "Object"+this._id;
}
}());
After that key of c[a] will be c["Object1"] and c[b] will be c["Object2"] and so on... and the c[a] == a and c[b] == b are working as expected, but in real life this is not a good solution.
An acceptable way to solve this would be either use some other key, perhaps an ID assigned to the object like c[a.id] = a or to use ES6 Map Object, where any value, including Objects, can be used as a key.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
The Map object is a simple key/value map. Any value (both objects and primitive values) may be used as either a key or a value.
I experimented with it a lit bit and @royhowie might be right. As you can see in this implementation I switched the order of the assignments and then c[a] == a gave a true.
var a = new Object;
var b = new Object;
var c = new Object;
//I switched the following lines of code
c[b]=b;
c[a]=a;
console.log(c[a]===a);
Output: true
c.a = a
orc['a'] = a
. That's for setting property names as if you were giving it a string.c[a]
sets the property name to be the same as the value ofa
, a variable. – user4698813 Commented May 9, 2015 at 4:54console.log(c);
Mystery solved. Question is mundane. – Niet the Dark Absol Commented May 9, 2015 at 14:45