【问题标题】:Define a custom hash() method for use with ES6 maps定义用于 ES6 映射的自定义 hash() 方法
【发布时间】:2015-10-13 11:49:13
【问题描述】:

为了说明问题,考虑以下简单对象

function Key( val ) {
  this._val = val;
}

现在我创建一个 ES6 Map 实例并像这样向其中输入一个条目

var map = new Map(),
    key1 = new Key( 'key' );

map.set( key1, 'some value' );

console.log( 'key1: ', map.has( key1 ) );
// key1:  true

到目前为止一切都很好。然而,挑战来了,如果我像这样创建一个几乎相同的对象key2

var key2 = new Key( 'key' );

所以基本上两个键是相同的,但显然key2 不是地图的一部分

console.log( 'key2: ', map.has( key2 ) );
// key2:  false

JavaScript 在这里使用对象引用作为键,因此两个单独的对象不会指向同一个值。

我现在想做的是,在键的prototype 中添加类似hash() 的方法,以便两个对象都指向同一个键。这样的事情可能吗?


我知道,有一种方法可以使用 Key 生成的工厂模式以及一些缓存来规避该问题。然而,这导致了很多关于对象不变性和缓存防止旧对象被垃圾收集的问题。所以我认为这不是一个真正的选择。

【问题讨论】:

标签: javascript dictionary ecmascript-6


【解决方案1】:

我在我的库 big-m 中创建了一个名为 CanonMap 的类,以通过哈希而不是引用来封装映射。

默认情况下,它适用于元组、日期和简单对象:

const { CanonMap } = "big-m";

const myMap = new CanonMap();
myMap.set(
  ["Farooq", "867-5309"],
  36.59
);

myMap.get(
  ["Farooq", "867-5309"]
) === 36.59;

myMap.set(
  {name: "Farooq", number: "867-5309"},
  36.59
);

myMap.get(
  {number: "867-5309", name: "Farooq"} // Insensitive to key ordering
) === 36.59;

myMap.set(new Date(2012, 6, 5), "Tuesday");
myMap.get(new Date(2012, 6, 5)) === "Tuesday";

它还可以使用自定义的“canonizer”函数进行扩展,该函数确定如何对值进行哈希处理:

import {naiveCanonize, jsonCanonize, JsonCanonMap, CanonMap} from "big-m";

// Same as default canonizer, but with greater recursion depth (default is 2)
new CanonMap([], 6);

// Canonize by ID with fallback to naive
const customCanonMap = new CanonMap([
  [{id: "TEST1", x: 7}, 77],
  [{ x: 7 }, 88]
], lookup => lookup.id || naiveCanonize(lookup));

customCanonMap.get({id: "TEST1", x: 8}) === 77; // Ignores other values, uses ID
customCanonMap.get({x: 8}) === undefined; // Uses all fields, so lookup fails

// Default canonizer with JSON.stringify
new CanonMap([], jsonCanonize);
// equivalent to
new CanonMap([], lookup => JSON.stringify(lookup));
// also equivalent to
new JsonCanonMap(); 

最后,如您所描述的,要实现一个利用对象本身的原型哈希函数的 CanonMap,您可以执行以下操作:

const selfHashingCanonMap = new CanonMap([], lookup => {
  if ("hash" in lookup) {
    return lookup.hash();
  } else {
    return naiveCanonize(lookup);
  }
});

【讨论】:

    【解决方案2】:

    这样的事情可能吗?

    不,这是 ES6 集合的一个已知缺陷。他们所做的只是检查参考身份,没有办法改变它。

    你能做的最好的事情(如果你说的哈希consing实例不是一个选项)是不要使用对象作为键。相反,使用对Key 值进行编码的字符串,并在两种表示形式之间来回转换。鉴于您认为您的密钥是不可变的,这应该不会造成问题。

    【讨论】:

      猜你喜欢
      • 2018-07-09
      • 2017-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-17
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多