使用 Array 对象作为 ES6 Map 的键

Using Array objects as key for ES6 Map

我正在尝试将我的代码更新为 ES6,因为我正在使用 Node 4.0,目前为止我非常喜欢它的功能。但是,我对新的 ES6 Map 数据结构有疑问,因为当使用 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

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

试试这个:

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

由于地图 class 旨在用作基础 class,您可以实现具有覆盖 .get() 功能的子class,也许。

(第一句中的"almost"是为了反映Map key的相等性比较是通过Object.is()来完成的,这在日常编码中并不多见。它本质上是一个第三个 JavaScript 中平等测试的变体。)

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

我也有这个需求,所以我写了一个 ISC 许可的库:array-keyed-map. You can find it on npm. I think the source 很清楚,但无论如何它是这样工作的,为了后代:


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

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

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

例如,在 akmap.set(['a', 'b'], true) 上,内部树结构是这样的——

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

之后执行 akmap.set(['a'], 'okay') 只会更改 'a':

处路径的值
'a':
  [value]: 'okay'
  'b':
    [value]: true

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

要删除数组的值,执行相同操作但删除 [value]-symbol-key 下的任何值,并在递归步骤后删除任何以 [=21 结尾的子树=] 的 0.


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

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

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