【问题标题】:Why is object[key] not equal to key, if key is an object, in JavaScript?为什么在 JavaScript 中,如果 key 是对象,object[key] 不等于 key?
【发布时间】:2015-05-09 04:44:03
【问题描述】:
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

为什么?

【问题讨论】:

  • 你为什么要这样做?
  • @VikashKesarwani - 这是一个很好的问题。很可能他将问题简化为一个简单的例子。
  • 它不像你在 c++ 中所做的那样指向,这是分配问题。这种自我披露的形式没有解决方案
  • 你想做c.a = ac['a'] = a。这是为了设置属性名称,就好像你给它一个字符串一样。 c[a] 将属性名称设置为与变量a 的值相同。
  • console.log(c); 谜团解开了。问题很普通。

标签: javascript


【解决方案1】:

这里的问题与如何设置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`)

【讨论】:

  • 没错,正如我在上面的评论中提到的自我披露分配的注释
  • a.toString()不是字符串"[object Object]"吗?
  • @slebetman 你是对的;我在想JSON。我会解决这个问题(尽管它是相同的概念)
  • @2pha 您将执行c['[object Object]'] = {},这将使c 数组保持不变,因为您通过字符串而不是索引访问它。
  • @2pha 我重写了我的答案并试图使其更简洁。你所写的正是发生的事情。
【解决方案2】:

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

所以,当你这样做时:

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

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

但是,它并没有失败,因为 JavaScript 可以解决这个问题。首先它发现

  1. 变量是一个对象,并且
  2. 变量具有 toString -function

因此,JavaScript 编译器将调用每个变量的 toString()。默认情况下,Object.prototype.toString 它将返回“[object Object]”-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 和 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 对象是一个简单的键/值映射。任何值(对象和 原始值)可以用作键或值。

【讨论】:

  • 谢谢。现在这个问题更清楚了,但我仍然对如何按照你的建议使用 c[a.id] 感到困惑
  • 这取决于您打算做什么,但是如果您想从“哈希”c 中查找对象,您可以为每个对象分配一个唯一的 ID,例如 obj.id = 1234;然后将值赋值给 c 像 c[obj.id] = obj;然后如果要从哈希中查找对象,请使用 c[] 或 c[someObject.id] 等进行搜索。
【解决方案3】:

我稍微尝试了一下,@royhowie 可能是对的。正如你在这个实现中看到的,我切换了分配的顺序,然后 c[a] == 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);

输出:真

【讨论】:

  • 是的,你的开关让情况完全不同。
猜你喜欢
  • 2012-06-17
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 1970-01-01
  • 2015-07-22
  • 2019-06-15
  • 1970-01-01
相关资源
最近更新 更多