34

我正在尝试将我的代码更新为 ES6,因为我使用的是 Node 4.0,并且到目前为止非常喜欢它的功能。但是,我对新的 ES6Map数据结构有疑问,因为它的行为与用作键{}时不同。Array我将它用作计数器地图。

我运行这段代码,我想知道如何使用数组作为Map.

"use strict";

var a = new Map();
a.set(['x','y'], 1);
console.log(a.get(['x','y']));

var b = {};
b[['x','y']] = 1;

console.log(b[['x','y']]);

它打印出以下内容,第一行应该是1而不是undefined

undefined
1

原始的 JS 映射对键进行字符串化,我不想对新的 ES6 进行相同类型的字符串化破解Map

对于 ES6,我能做些什么来可靠地使用数组作为键Map

4

4 回答 4

15

了解 ES2015 Map 键的比较(几乎)就像与===运算符一样。两个数组实例,即使它们包含相同的值,也永远不会===相互比较。

尝试这个:

var a = new Map(), key = ['x', 'y'];
a.set(key, 1);
console.log(a.get(key));

由于 Map 类旨在用作基类,因此您可能可以实现具有覆盖.get()函数的子类。

(第一句中的“几乎”是为了反映 Map 键相等比较是通过 完成的这一事实Object.is(),这在日常编码中并不多见。它本质上是 JavaScript 中相等测试的第三种变体。)

于 2015-09-18T20:07:26.130 回答
8

我也有这个需求,所以我写了一个 ISC 授权的库:array-keyed-map。你可以在 npm 上找到它。我认为来源很清楚,但无论如何,为了后代,它是这样工作的:


维护Map对象树。每棵树存储:

  • 在内部声明的Symbol键下:树中该点的值(如果有)。保证唯一性,因此Symbol没有用户提供的值可以覆盖此键。

  • 在它的所有其他键上:到目前为止所有其他从这棵树设置的下一个树。

例如,在 上akmap.set(['a', 'b'], true),内部的树形结构就像——</p>

'a':
  [value]: undefined
  'b':
    [value]: true

在那之后做akmap.set(['a'], 'okay')只会改变路径的值'a'

'a':
  [value]: 'okay'
  'b':
    [value]: true

要获取数组的值,请在从树中读取相应键的同时遍历数组。undefined如果任何点的树都不存在,则返回。[value]最后,从你得到的树上读取内部声明的符号。

要删除数组的值,请执行相同操作,但删除[value]-symbol-key 下的所有值,并在递归步骤后删除任何以 asize为 0 的子树。


为什么是树?因为当多个数组具有相同的前缀时它非常有效,这在实际使用中非常典型,用于处理例如文件路径。

于 2019-04-08T07:34:49.483 回答
7

Array您需要保存对用作键的非原始实例的引用。请注意以下两个示例的区别:

"use strict";

var a = new Map();
a.set(['x','y'], 1);
console.log(a.get(['x','y']));
console.log(['x','y'] === ['x','y']);

var b = new Map();
var array = ['x','y'];
b.set(array, 1);
console.log(b.get(array));
console.log(array === array);

于 2017-07-11T18:12:43.900 回答
2

如果有人在这里寻找更基本的方法,您可以将自定义的键一对一转换为字符串,例如${x}_${y}(依赖于特定的键结构)或JSON.stringify(key)(更通用) - 这绝不是一个完美的解决方案,但在许多情况下它可能是最可靠的。

我知道 OP 要求其他方法,但我认为这里仍然需要提到这个方法,作为对标题问题的最直接答案。

于 2021-10-18T15:21:40.147 回答