如何在 Typescript: for...in 中迭代映射?为了……的?对于每个?

Kat*_*ine 7 javascript dictionary for-loop typescript

我试图理解在 Typescript 中迭代映射的语法。我的地图中的键是字符串。这些值是字符串数组。

这是一些示例代码:

let attributeMap: Map<string, string[]> = new Map<string, string[]>();

// sample data
let sampleKey1 = "bob";

// populate map
let value: string[] = attributeMap.get(sampleKey1) || [];
value.push("clever");
attributeMap.set(sampleKey1, value);

value = attributeMap.get(sampleKey1) || [];
value.push("funny");
attributeMap.set(sampleKey1, value);


// try looping through the map
for (let key in attributeMap) {
    console.log(attributeMap.get(key));
    console.log("WE'RE IN THE MAP!");
}

console.log("done");
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,唯一打印的内容是“完成”。

为什么地图上没有打印任何内容,也没有显示“我们在地图上”的消息?就好像 for 循环从未进入过一样。这是为什么?我该如何解决这个问题?

Cer*_*nce 9

当您将键设置为 Map 时,键不会放入 Map 实例中 - 它们存储在 Map内部,并且只能通过使用各种 Map 迭代方法之一进行访问。仅直接for..in迭代对象或其原​​型上的属性。

要迭代 Map,请尝试这样的操作:

for (const [key, value] of attributeMap.entries()) {
  console.log(key, value);
}
Run Code Online (Sandbox Code Playgroud)

for..in当您的集合是对象本身具有键值对的普通对象时,这是有意义的,但对于 Maps 来说则不然,因为 Maps 以不同的方式存储数据。

当属性直接位于对象上时,语法通常如下所示:

someObj.someProp = 'someVal';
Run Code Online (Sandbox Code Playgroud)

这会将someProp属性添加到对象上someObj

但是 Map 将其数据存储在Map 的[[MapData]]内部槽中,而不是直接存储在 Map 的不同属性上。

正如理论练习一样,在 JS 中,您可以将属性直接放在 Map 实例上,然后对其进行迭代for..in(基本上,将地图滥用为具有自己属性的对象):

const map = new Map();
map.foo = 'bar';
for (const prop in map) {
  // ...
}
Run Code Online (Sandbox Code Playgroud)

但这完全是一种反模式,永远不应该这样做。使用对象并通过点和括号表示法(以及其他对象方法,如Object.entries)来设置/检索属性,或者使用 Map 并通过Map.getMap.set以及其他 Map 方法来设置/检索属性。

  • 迭代器很棒。如果您想用现代语法编写源代码(您应该这样做!),我建议打开 `downlevelIteration`,请参阅:/sf/ask/3740890471/默认开启。映射迭代使用迭代器,而不是数组,因此无论如何您可能都需要“downlevelIteration”。 (2认同)
  • `Object.keys` 使用与 `for..in` 非常相似的逻辑 - 它仅迭代*直接在对象*上的属性。但 Map 属性并不存储在地图实例上,而是存储在“MapData”槽内(它不直接暴露给 JS,除非通过特定于 Map 的迭代方法)。 (2认同)
  • 当然,如果您对代码的外观感到满意,那就没问题了。它不像我个人喜欢的那么简洁,但也没有什么问题。 (2认同)