ES6 中的地图与对象,何时使用?

Maps vs Objects in ES6, When to use?

Ref: MDN Maps

Use maps over objects when keys are unknown until run time, and when all keys are the same type and all values are the same type.

Use objects when there is logic that operates on individual elements.

问题:

在对象上使用地图的适用示例是什么?特别是 "when would keys be unknown until runtime?"

var myMap = new Map();

var keyObj = {},
    keyFunc = function () { return 'hey'},
    keyString = "a string";

// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");

console.log(myMap.get(keyFunc));

What is an applicable example of using Maps over objects?

我认为你已经给出了一个很好的例子:当你使用对象(包括 Function 对象)作为键时,你至少需要使用 Maps。

in particular, "when would keys be unknown until runtime?"

只要它们在编译时是未知的。简而言之,当您需要 key-value collection 时,您应该始终使用 Map。当您从集合中动态添加和删除值时,尤其是当您事先不知道这些值时(例如,它们是从数据库中读取的,由用户输入的,等等),您需要一个集合的一个很好的指标。

相比之下,当您在编写代码时知道对象具有哪些属性和多少属性时,您应该使用对象 - 当它们的形状是静态的。正如@Felix 所说:当你需要 record 时。当字段具有不同类型时,以及当您永远不需要使用括号表示法(或期望其中包含一组有限的 属性 名称)时,一个很好的指标就是需要它。

Use maps over objects when keys are unknown until run time, and when all keys are the same type and all values are the same type.

我不知道为什么有人会写出如此明显错误的东西。我不得不说,最近人们在 MDN 上发现越来越多的错误 and/or 有问题的内容。

这句话没有一点是对的。使用映射的主要原因是当您需要对象值键时。值应该是同一类型的想法是荒谬的——当然它们可能是。在 运行 之前密钥未知时不应该使用对象的想法同样荒谬。

我认为使用 ES2015 的 Map 只有两个原因可以使用普通对象:

  • 您根本不想遍历对象类型的属性
  • 或者你这样做,但 属性 顺序并不重要,你可以 distinguish the program from the data level 在迭代时

什么时候 属性 命令不重要?

  • 如果您只有一个值和一些应该与其显式关联的函数(例如 Promise - 它是未来值的代理 - 和 then/catch)
  • 如果您有一个 struct/record-like 数据结构,其中一组静态属性在 "compile time" 处已知(通常 structs/records 不可迭代)

在所有其他情况下,您可能会考虑使用 Map,因为它保留了 属性 顺序并将程序(分配给 Map 对象的所有属性)与数据级别( Map 本身中的所有条目)。

Map有什么缺点?

  • 你失去了简洁的对象字面量语法
  • 您需要 JSON.stringyfy
  • 的自定义替换器
  • 你失去了解构,无论如何这对静态数据结构更有用

此问题与 but until it's closed, here's my answer from over there 重复:

除了其他答案之外,我还发现使用地图比使用对象更笨拙和冗长。

obj[key] += x
// vs.
map.set(map.get(key) + x)

这很重要,因为更短的代码阅读起来更快,表达更直接,也更好kept in the programmer's head

另一个方面:因为 set() returns 映射,而不是值,所以不可能链式赋值。

foo = obj[key] = x;  // Does what you expect
foo = map.set(key, x)  // foo !== x; foo === map

调试地图也比较痛苦。在下面,您实际上看不到地图中有哪些键。您必须编写代码才能做到这一点。

对象可以被任何IDE:

求值

MapObject的区别之一是:

Map 可以使用复杂数据类型作为它的键。像这样:

const fn = function() {}
const m = new Map([[document.body, 'Whosebug'], [fn, 'redis']]);

m.get(document.body) // 'Whosebug'
m.get(fn) //'redis'

注意: 对于复杂数据类型,如果要获取值,必须传递与键相同的引用。

Object,它只接受简单数据类型(numberstring)作为它的键。

const a = {};
a[document.body] = 'Whosebug';

console.log(a) //{[object HTMLBodyElement]: "Whosebug"}

Objects 与 Maps 的相似之处在于,两者都允许您将键设置为值、检索这些值、删除键以及检测键中是否存储了某些内容。正因为如此(并且因为没有内置的替代品),Objects 在历史上一直被用作 Maps;然而,在某些情况下使用 Map 更可取的重要区别是:

  • Object 的键是 StringSymbol,而它们可以是 Map 的任何值,包括函数、对象和任何原语。
  • Map 中的键是有序的,而添加到对象的键不是。因此, 遍历它时,Map 对象 returns 键的顺序 插入。
  • 您可以使用 size 属性 轻松获得 Map 的大小,而 Object 中的属性数量必须手动确定。
  • A Map 是可迭代的,因此可以直接迭代,而 迭代 Object 需要以某种方式获取它的键 并遍历它们。
  • 一个Object有一个原型,所以映射中有默认键 如果您不小心,可能会与您的钥匙发生碰撞。从 ES5 开始 可以使用 map = Object.create(null) 绕过,但这是 很少做。
  • A Map可能在频繁加法和加法的场景表现更好 删除密钥对。

MDN