代码之家  ›  专栏  ›  技术社区  ›  Stav Alfi

为什么一个对象中有两个不同的键互相覆盖?

  •  6
  • Stav Alfi  · 技术社区  · 6 年前

    我分配了以下三个变量:

    const a = {key:true}
    const b = {key:false}
    const c = {[a]:'1',[b]:'2'}
    

    当我尝试将以下内容登录到控制台时:

    console.log(c[a],c[b])
    

    我得到了以下信息:

    2 2
    

    当我认为我应该得到:

    1 2
    

    为什么我错了,我该怎么修复它?

    4 回复  |  直到 6 年前
        1
  •  2
  •   Nina Scholz    6 年前

    你可以看看 c ,在这里您可以看到 a.toString()

    const a = { key: true }
    const b = { key: false }
    const c = { [a]: '1', [b]: '2' }
    
    console.log(c);
    console.log(c[a], c[b]);

    为了克服这个问题,可以使用JSON字符串

    const a = { key: true }
    const b = { key: false }
    const c = { [JSON.stringify(a)]: '1', [JSON.stringify(b)]: '2' }
    
    console.log(c);
    console.log(c[JSON.stringify(a)], c[JSON.stringify(b)]);

    特别是对于作为键的对象,可以使用 WeakMap :

    const a = { key: true }
    const b = { key: false }
    const c = new WeakMap([[a, '1'], [b, '2']]);
    
    console.log(c.get(a), c.get(b));
        2
  •  9
  •   AndrewL64    6 年前

    对象只能有字符串(或符号)作为其键。如果尝试使用非字符串,它将转换为字符串。所以当你设定 c[a] 成为 1 , a 是一个对象,这意味着它需要转换为字符串。所以你最终会设置 c["[object Object]"] 成为一体。然后当你设置 c[b] ,你做同样的事情,再次转换为 "[object Object]" 从而覆盖已经存在的值。

    尝试注销 c 看到这一点:

    const a = {key:true}
    const b = {key:false}
    const c = {[a]:'1',[b]:'2'}
    console.log(c);

    需要将对象用作键是不常见的,但如果需要,可以使用 Maps 而不是对象

    const a = {key:true}
    const b = {key:false}
    const c = new Map();
    c.set(a, '1');
    c.set(b, '2');
    console.log(c.get(a));
    console.log(c.get(b));
        3
  •  4
  •   Felix Kling    6 年前

    为什么我错了,我该怎么修复它?

    对象属性名称转换为字符串(如果不是字符串或符号)。对象值默认序列化为 [object Object] ,因此对于javascript,这两个值是相同的:

    const a = {key:true}
    const b = {key:false}
    
    console.log('a', a.toString());
    console.log('b', b.toString());

    1。 你可以实现你自己的 toString 方法将对象序列化为不同的字符串:

    function toString() {
      return this.key.toString();
    }
    
    const a = {key:true, toString}
    const b = {key:false, toString}
    const c = {[a]:'1',[b]:'2'}
    console.log(c[a],c[b]) 

    但这并不能使您恢复用作密钥的原始值(您 能够 使用对象的JSON表示形式作为键,您可以将其转换回对象,但这仅在“键对象”仅包含可以用JSON表示的值时才有效。


    2。 你可以使用 Map 而不是允许任意值作为键的对象:

    const a = {key:true}
    const b = {key:false}
    const c = new Map([[a, '1'], [b, '2']]);
    console.log(c.get(a),c.get(b)) 

    注意 地图 s使用对象标识查找值,因此 c.get({key: false}) 不会起作用。


    走哪条路真的取决于你需要什么。

        4
  •  1
  •   AndrewL64    6 年前

    JavaScript对象键是字符串(或可选符号,但既不在这里也不在那里)。如果您console.log(c),您将看到它是[对象对象对象]:“2”,因为[a]和[b].ToString()都是“[对象对象对象]”

    至于“修复”它…我不明白你想实现什么,所以我不能帮你,对不起。