[Javascript Tips] Using Map over Object
In Javascript, if you are using Object to store key-valeu pairs while you will be adding and deleting keys frequently, then you should use Map instead.
Because Map have optimzation for deletion but Object has not.
const eventsMap = {}
eventsMap[myEvent.id] = myEvent
delete eventsMap[myEvent.id] // slower
const eventsMap = new Map()
eventsMaps.set(myEvent.id, myEvent)
eventsMaps.delete(myEvent.id) // faster
No polluted built-in values
Other issues, for example, Object are polluted with tons of keys built into them already.
All those built in props have value already:
const eventsMap = {}
eventsMap.valueOf() // {}
But for Map, you don't have this problem:
const eventsMap = new Map()
eventsMap.get(valueOf) // undefined
WeakMap
for Map, you can use any value as key, even DOMnode or an empty object or any reference
const metadata = new Map()
metadata.set({}, 'value')
metadata.set(DOMNode, 'value')
metadata.set(myEvent, {...})
But there is one problem, for example metadata.set(myEvent, {...})
, if for myEvent
, any reference to it has been removed, it should be garbage collected, but because of Map is holding the reference, it might cause memory leak.
That's why we can use WeakMap
const metadata = new WeakMap()
metadata.set(myEvent, {...})
If other reference to myEvent
has been removed, it will be automaticlly garbage collected as well to prevent memory leak.
Iterating over Object vs Map
When interating over an object, you have to do this:
const eventsMap = {}
// option 1: eventsMap.hasOwnProperty
// problem: it can be overwritten
for (const key in eventsMap) {
if (eventsMap.hasOwnProperty(key)) {
// logic here
}
}
// option 2: Object.property.hasOwnProperty
// safer than option 1
// problem: too urgly
for (const key in eventsMap) {
if (Object.property.hasOwnProperty.call(eventsMap, key)) {
// logic here
}
}
// option 3: Object.keys
Object.keys(eventMap).map(key => {...})
Map doesn't have those problem, and Map can preserve the order of the keys, and becasue Map is iterable, you can use destructuring to grab the first key and value
const eventsMap = new Map()
const [[firstKey, firstValue]] = eventsMap