如果key是一个对象,为什么对象[key]不等于key?

时间:2015-05-09 04:44:03

标签: javascript

var a = new Object;
var b = new Object;
var c = new Object;

c[a] = a;
c[b] = b;

console.log(c[a] === a);

我测试了上面的代码并得到false。如果我尝试console.log(c[a] === b),则会打印true

为什么?

3 个答案:

答案 0 :(得分:33)

此处的问题与Object键的设置方式有关。来自MDN

  

参数

     

nameValuePair1,nameValuePair2,... nameValuePairN

     
      
  • 成对的名称(字符串)和值(任何值),其中名称通过冒号与值分隔。
  •   
     

<强>值

     
      
  • 任何价值。
  •   

可以通过三种方式(通过适当的密钥)访问对象的值:

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
}
*/

使用括号表示法时,需要注意括号之间的间隙!对象使用toString方法设置其键和值,除非它们传递了一个字符串(然后toString中没有任何一点)。使用点表示法时,他们使用.key作为键。

让我们来看看你的情况:

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`)

答案 1 :(得分:7)

Object不是JavaScript Object的有效键,只有字符串

所以,当你这样做时:

c[a] = a;
c[b] = b;

编译器不能像c [a]或c [b]那样使用a或b作为c的键。

然而,它并没有失败,因为JavaScript可以解决这个问题。首先,它确定了

  1. 变量是一个对象
  2. 变量具有toString -function
  3. 因此,JavaScript编译器将调用每个变量的toString()。并且默认情况下,它将返回Object.prototype.toString&#34; [object Object]&#34; -string,因为实现是执行该操作的默认实现,并且该值成为新键

    c["[object Object]"] = a;
    c["[object Object]"] = b; // overrides the previous
    

    这不是你想要的。问题是toString默认返回总是相同的值,因此分配将始终转到相同的键。

    为了证明toString实际上是问题,你实际上可以做一个可怕的作弊来让每个对象都返回唯一的字符串

    // don't do this!!! 
    (function() {
      var id=1;
      Object.prototype.toString = function() {
       if(!this._id) this._id = id++;
       return "Object"+this._id;
      }
    }());
    

    c [a]的关键是c [&#34; Object1&#34;],c [b]将是c [&#34; Object2&#34;]等等......等等c [a] == a和c [b] == b按预期工作,但在现实生活中这不是一个好的解决方案。

    解决这个问题的一种可接受的方法是使用一些其他键,可能是分配给对象的ID,如c [a.id] = a或使用ES6 Map Object,其中可以使用包括Objects在内的任何值作为关键。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

      

    Map对象是一个简单的键/值映射。任何价值(对象和   原始值)可以用作键或值。

答案 2 :(得分:-2)

我尝试了一点点,@ royhowie可能是对的。正如你在这个实现中看到的那样,我切换了赋值的顺序,然后c [a] == a给出了一个真值。

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);

输出:true