JavaScript中以同类对象实例为字典键时,如何避免键被覆盖?
问题:JavaScript对象作为键时被覆盖,无法实现C#字典的效果
我尝试了以下JavaScript代码,但最终字典中只有一个键:
class dog {} dic = {} for (let i = 0; i < 3; i++) { dic[new dog()] = i; } for (var item in dic) { console.log(dic[item]); }
这并非我想要的效果,我希望实现如下C#代码的效果,其输出为0 1 2。看起来上述JS代码中的每个new dog()都被视为同一个对象,导致值被覆盖。请问如何修改JS代码以实现如下C#代码的效果?
using System; using System.Collections.Generic; class dog { } public class Program { public static void Main() { var dic = new Dictionary<object,int>(); for(var i=0; i<3; i++) { dic[new dog()] = i; } foreach(var item in dic.Keys) { Console.WriteLine(dic[item]); } } }
问题原因
JavaScript里普通对象作为另一个对象的键时,会被自动转换为字符串[object Object],所以每次new dog()生成的实例都会被转成同一个字符串键,导致后续值直接覆盖之前的。而C#的Dictionary<object, int>是基于对象引用或Equals方法区分键的,和JS普通对象的行为完全不同。
解决方法
方法1:使用Map(推荐)
ES6引入的Map原生支持用对象作为键,它会基于对象的引用关系区分不同键,和C#字典的行为一致:
class dog {} const dic = new Map(); for (let i = 0; i < 3; i++) { dic.set(new dog(), i); } // 遍历输出值 for (const value of dic.values()) { console.log(value); } // 输出:0 1 2
方法2:给对象添加唯一标识作为键
如果必须使用普通对象作为字典容器,可以给每个dog实例添加唯一属性,用该属性作为键:
class dog { constructor() { // 用Symbol生成全局唯一标识,也可以用自增数字 this.uniqueKey = Symbol(); } } const dic = {}; for (let i = 0; i < 3; i++) { const dogInstance = new dog(); dic[dogInstance.uniqueKey] = i; } for (const key in dic) { console.log(dic[key]); } // 输出:0 1 2
说明
Map是最贴合需求的方案,它的API(set/get/has等)专门针对键值对设计,处理对象键更直观可靠。- 用唯一标识作为普通对象键时,Symbol是最优选择,因为每个Symbol都是全局唯一的,不会出现字符串键的冲突问题。
内容的提问来源于stack exchange,提问作者Damn Vegetables
相关产品推荐
相关产品推荐

