在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

为什么?

这里的问题与如何设置Object的键有关。来自MDN:

参数

nameValuePair1,nameValuePair2,... nameValuePairn

  • 对名称(字符串)和值(任何值)的对,其中名称与值与值分开的名称。

value

  • 任何值。

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

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

对象不是JavaScript对象的有效键,只有字符串为

所以,当您这样做时:

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

编译器不能将A或B用作C [A]或C [B]中的C键。

但是,它不会失败,因为JavaScript可以解决此问题。首先,它弄清楚

  1. 变量是对象,
  2. 变量具有tostring -function

因此,JavaScript编译器将调用每个变量的ToString()。默认情况下,object.prototype.tostring将返回" [对象对象]" -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 [" object1"],而c [b]将为c [object2']等...以及c [a] == a and c [B] == B正在按预期工作,但是在现实生活中,这不是一个好的解决方案。

解决此问题的一种可接受的方法是使用其他键,也许是分配给诸如c [a.id] = a或使用es6 map对象的对象的ID,其中任何值(包括对象)都可以使用作为钥匙。

https://developer.mozilla.org/en-us/docs/web/javascript/reference/global_objects/map

地图对象是一个简单的密钥/值映射。任何值(两个对象和 原始值)可以用作键或值。

我尝试了一点,@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

相关内容

最新更新