最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Why is object[key] not equal to key, if key is an object, in JavaScript? - Stack Overflow

programmeradmin14浏览0评论
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
  • Why are you even doing this? – Vikash Kesarwani Commented May 9, 2015 at 4:47
  • 16 @VikashKesarwani - this is a good question. Most likely he's reduced the problem to an simple example. – Martin Konecny Commented May 9, 2015 at 4:48
  • Its not pointing like that which you had done in c++, Here is assignment problem. and there is no solution for this self disclosed form – Janak Dhanani Commented May 9, 2015 at 4:49
  • You want to do c.a = a or c['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 of a, a variable. – user4698813 Commented May 9, 2015 at 4:54
  • 1 console.log(c); Mystery solved. Question is mundane. – Niet the Dark Absol Commented May 9, 2015 at 14:45
Add a comment  | 

3 Answers 3

Reset to default 35

The 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

  1. The variable is an object and
  2. 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

发布评论

评论列表(0)

  1. 暂无评论