Javascript 定义用于ES6映射的自定义哈希()方法 为了说明问题,请考虑下面的简单对象 function Key( val ) { this._val = val; }

Javascript 定义用于ES6映射的自定义哈希()方法 为了说明问题,请考虑下面的简单对象 function Key( val ) { this._val = val; },javascript,dictionary,ecmascript-6,Javascript,Dictionary,Ecmascript 6,现在,我创建了一个ES6Map实例,并向其中输入一个条目,如下所示 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' ); 所以基

现在,我创建了一个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在这里使用对象引用作为键,因此两个单独的对象不会指向相同的值

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


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

这样的事情可能吗

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


您可以做的最好的事情(如果哈希考虑实例不是您所说的选项)是不使用对象作为键。相反,使用对
值进行编码的字符串,并在两种表示之间来回转换。假设你认为你的密钥是不可变的,这不应该造成问题。

< P>我在库中创建了一个名为Con映射的类来封装哈希而不是引用的映射。< /P> 默认情况下,它适用于元组、日期和简单对象:

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);
  }
});
另见