ES6 Maps makes it possible to use keys with any value, including functions, objects, and any primitive. I would like to create a combined key with a string and a reference to a DOM-node.
var map = new Map();
var myKey = document.body + 'my string'
map.set(myKey, 'my value')
Obviously this will not work, the addition above will evaluate to [object HTMLBodyElement]my string
. How would I go about doing this?
You can't do what you literally described, but you can have a map of maps. I'd probably use a 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
keyed by the relevant string. E.g.:
let entriesByElement = new WeakMap();
Setting an element:
let map = entriesByElement.get(document.body);
if (!map) {
map = new Map();
entriesByElement.set(document.body, map);
}
map.set(keyString, value);
Getting an element:
let map = entriesByElement.get(document.body);
let value = map && map.get(keyString);
(That example assumes you won't have undefined
as a valid stored value.)
You could wrap that up in a class.
Example:
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>