Typescript:使用日期作为地图中的键?

jmg*_*net 12 dictionary date typescript angular

在我的应用程序中,我需要每个日期的对象地图。由于打字稿既有 aMap又有 aDate对象,我希望这很简单。

  let map: Map<Date, MyObject> = new Map<Date, MyObject>();
Run Code Online (Sandbox Code Playgroud)

并用于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.
  });
Run Code Online (Sandbox Code Playgroud)

为什么除非使用完全相同的实例,否则我无法从地图中获取值?

小智 11

它总是错误的,因为这两个日期对象是不同的可变 JavaScript 对象。

new Date(2019, 11, 25) === new Date(2019, 11, 25) ==> false

你可以看看这个帖子里的答案。


Kin*_*oja 5

最好使用原始值(数字、字符串)作为 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()))
Run Code Online (Sandbox Code Playgroud)

我在上述评论中提供了此类行为的链接。


Plo*_*hie 5

这是 的核心逻辑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
Run Code Online (Sandbox Code Playgroud)

在获取值时map,不考虑键数据,而是搜索键的唯一标识。当您创建不可变对象时,每个对象可能具有相同的数据,但每个对象的引用将不同。因此它将被视为不同的密钥。

解决方案是使用在整个程序中可以具有相同引用的类型,例如字符串文字。

再举一个例子,

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
Run Code Online (Sandbox Code Playgroud)

  • 问题不在于可变性,而在于平等。可变性仅在映射的实现中很重要,其中相等性检查取决于可以更改的数据。JavaScript 的“Map”使用引用相等性,即使对象发生变异,引用相等性也不会改变,因此如果需要,您可以拥有可变的对象键,而不会破坏“Map”。不幸的是,这也意味着在使用“Map”时必须保留对象键,因为无法获得与旧对象相同的新对象。 (3认同)