打字稿:在地图中使用日期作为键?
Posted
技术标签:
【中文标题】打字稿:在地图中使用日期作为键?【英文标题】:Typescript: using Date as key in Map? 【发布时间】:2020-04-08 07:04:57 【问题描述】:在我的应用程序中,我需要每个日期的对象地图。由于 typescript 有一个 Map
和一个 Date
对象,我希望这很简单。
let map: Map<Date, MyObject> = new Map<Date, MyObject>();
并使用set
添加新的键和值对。但后来我意识到我不能get
使用日期的值,除非我使用完全相同的Date
实例。
我已经用它编写了一个单元测试:
it('Should not be a problem', () =>
let d1: Date = new Date(2019, 11, 25); // Christmas day
let d2: Date = new Date(2019, 11, 25); // Same Christmas day?
let m: Map<Date, string> = new Map<Date, string>();
m.set(d1, "X");
expect(m.get(d1)).toBe("X"); // <- This is OK.
expect(m.get(d2)).toBe("X"); // <- This test fails.
);
为什么我无法从地图中获取值,除非我使用完全相同的实例?
【问题讨论】:
我认为m.get(d2)
行不行,因为 Map 将每个 Date 键存储为单独的对象,无论它们是否是同一个 Date 实例。我建议将日期实例转换为字符串(例如使用方法toDateString()
),你会得到它。
你的意思是Date之间不相等?
不是真的,因为它们是对象,相等运算符检查它们是否是同一个实例。看看this post
【参考方案1】:
最好使用原始值(数字、字符串)作为 Map 键:
let m: Map<string, string> = new Map<string, string>();
let d1: Date = new Date(2019, 11, 25); // Christmas day
let d2: Date = new Date(2019, 11, 25); // Same Christmas day?
m.set(d1.toDateString(), "X");
console.log(d1.toDateString())
console.log(d2.toDateString())
console.log(m.get(d2.toDateString()))
我在上述 cmets 上提供了此类行为的链接。
【讨论】:
【参考方案2】:这总是虚假的,因为这两个日期对象是不同的可变 javascript 对象。
new Date(2019, 11, 25) === new Date(2019, 11, 25) ==> false
.
您可以在post 中查看答案。
【讨论】:
【参考方案3】:这是Map
的核心逻辑,正如你所知,map将值存储在键值对中。
对于键的比较,键应始终具有相同的引用。您可能知道字符串字面量引用在许多编程语言中是相等的,因此在 map 中首选使用字符串作为键。
上述行为不仅适用于date
,也适用于任何其他可变对象类型。
例如
let str1 = 'test';
let str2 = 'test';
str1 == str2; // true
let str1 = new String('test');
let str2 = new String('test');
str1 == str2; // false
从map
获取值时,不考虑keys数据,而是key的唯一标识是search。当您创建不可变对象时,每个对象可能具有相同的数据,但每个对象的引用会有所不同。因此它将被视为不同的键。
解决方案是使用可以在整个程序中具有相同引用的类型,例如字符串文字。
再举一个例子,
class Demo
field: string;
constructor(f: string)
this.field = f;
const d1 = new Demo('test');
const d2 = new Demo('test');
// both objects seems same by data, but there references are different
// hence will be treated as separate keys.
const m: Map<any, string> = new Map<any, string>();
m.set(d1, 'value1');
console.log(m.get(d1)); // value1
console.log(m.get(d2)); // undefined
【讨论】:
问题不在于可变性,而在于平等。可变性仅在等式检查依赖于可以更改的数据的 map 实现中很重要。 JavaScript 的Map
使用引用相等,即使对象发生了变异,它也不会改变,因此您可以在不破坏Map
的情况下拥有可变的对象键。不幸的是,这也意味着当您使用Map
时,您必须持有对象键,因为无法获得与旧对象相等的新对象。
@jcalz 同意。更新了我的答案。你觉得现在有意义吗?
是的,谢谢。如果有人关心我持有可变键的意思,here's an example。以上是关于打字稿:在地图中使用日期作为键?的主要内容,如果未能解决你的问题,请参考以下文章