Составление ключей к ES6 Map из примитивов и объектов - PullRequest
0 голосов
/ 29 июня 2018

ES6 Maps позволяет использовать ключи с любым значением, включая функции, объекты и любые примитивы. Я хотел бы создать комбинированный ключ со строкой и ссылкой на DOM-узел.

var map = new Map();
var myKey = document.body + 'my string'

map.set(myKey, 'my value')

Очевидно, что это не сработает, добавленное выше значение оценивается как [object HTMLBodyElement]my string. Как мне это сделать?

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Используя этот пользовательский MultiKeyMap, вы можете создать карту, которая принимает любые цифровые клавиши на основе номера, который вы передали constructor при его создании. Однако обратите внимание, что кортеж ключей упорядочен :

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))
0 голосов
/ 29 июня 2018

Вы не можете делать то, что буквально описали, но у вас может быть карта карт. Я бы, вероятно, использовал WeakMap с ключом ссылки DOM (чтобы он не заставлял элемент оставаться в памяти, если он был удален манипуляцией DOM), где значение равно Map вводится соответствующей строкой. E.g.:

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 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>
...