使用 Array 对象作为 ES6 Map 的键

IT技术 javascript arrays dictionary ecmascript-6 es6-map
2021-03-06 20:26:01

我正在尝试将我的代码更新为 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个回答

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

试试这个:

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

由于 Map 类旨在用作基类,因此您可以使用覆盖.get()函数实现子类,也许吧。

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

感谢您的详细回答,但覆盖.get()不是我想要做的
2021-04-25 20:26:01

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


维护Map对象每棵树存储:

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

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

例如,在 上akmap.set(['a', 'b'], true),内部树结构将类似于——

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

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

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

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

要删除数组的值,请执行相同的操作,但删除[value]-symbol-key下的所有值,并在递归步骤之后删除所有子树,如果它们以 asize为 0结束


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

您需要保存对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);

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

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