将键组合到由基元和对象组成的 ES6 Map

Composing keys to ES6 Map made of both primitives and objects

ES6 Maps 可以使用具有任何值的键,包括函数、对象和任何原语。我想创建一个包含字符串和对 DOM-node.

的引用的组合键
var map = new Map();
var myKey = document.body + 'my string'

map.set(myKey, 'my value')

显然这行不通,上面的加法将计算为 [object HTMLBodyElement]my string。我该怎么做?

你不能按照你字面上描述的那样去做,但你可以有地图中的地图。我可能会使用由相关字符串键入的 WeakMap keyed by the DOM reference (so that it doesn't force the element to remain in memory if it's removed by DOM manipulation), where the value is a Map 。例如:

let entriesByElement = new WeakMap();

正在设置元素:

let map = entriesByElement.get(document.body);
if (!map) {
    map = new Map();
    entriesByElement.set(document.body, map);
}
map.set(keyString, value);

正在获取一个元素:

let map = entriesByElement.get(document.body);
let value = map && map.get(keyString);

(该示例假定您不会将 undefined 作为有效存储值。)

您可以将其包装在 class 中。

示例:

class ExampleStore {
    constructor() {
        this.entriesByElement = new WeakMap();
    }
    set(element, string, value) {
        let map = this.entriesByElement.get(element);
        if (!map) {
            map = new Map();
            this.entriesByElement.set(element, map);
        }
        map.set(string, value);
    }
    get(element, string) {
        const map = this.entriesByElement.get(element);
        return map && map.get(string);
    }
}

const store = new ExampleStore();

let div1 = document.getElementById("one");
let div2 = document.getElementById("two");

store.set(div1, "a", "ayy");
store.set(div1, "b", "bee");

store.set(div2, "a", "alpha");

console.log(store.get(div1, "a")); // "ayy"
console.log(store.get(div1, "b")); // "bee"

console.log(store.get(div2, "a")); // "alpha"
console.log(store.get(div2, "b")); // undefined (doesn't have that entry)

// Removing div1
document.body.removeChild(div1);
div1 = null;

console.log(store.get(div1, "a")); // May be undefined, if the element has been
                                   // cleaned up (it is for me on Chrome,
                                   // Firefox and Edge), since we're using a
                                   // WeakMap.
<div id="one"></div>
<div id="two"></div>

使用此自定义 MultiKeyMap,您可以创建一个地图,该地图接受基于实例化时传递给 constructor 的数字的任何数字键。但是,请注意键的元组是 ordered:

class MultiKeyMap extends Map {
  constructor (keys = 1) {
    if (keys < 1) {
      throw new RangeError('keys must be greater than 0')
    }

    // 1 key is just a normal Map
    if (keys === 1) {
      return new Map()
    }

    super()
    this.keys = keys
  }
  
  get (key, ...keys) {
    if (arguments.length !== this.keys) {
      throw new RangeError('Unexpected number of keys')
    }

    // return early
    if (!super.has(key)) {
      return undefined
    }

    return super.get(key).get(...keys)
  }

  // (...keys, value) is an illegal signature
  set (key, ...args) {
    if (args.length !== this.keys) {
      throw new RangeError('Unexpected number of keys')
    }

    if (!super.has(key)) {
      super.set(key, new MultiKeyMap(this.keys - 1))
    }

    return super.get(key).set(...args)
  }
  
  has (key, ...keys) {
    if (arguments.length !== this.keys) {
      throw new RangeError('Unexpected number of keys')
    }

    return super.has(key) && super.get(key).has(...keys)
  }
}

const map = new MultiKeyMap(2)

map.set(document.body, 'my string', 'my value')

console.log(`document.body, 'my string'`)
console.log(map.has(document.body, 'my string'))
console.log(map.get(document.body, 'my string'))
console.log(`'my string', document.body`)
console.log(map.has('my string', document.body))
console.log(map.get('my string', document.body))