npm.io
2.4.0 • Published 6 years ago

hashmap

Licence
MIT
Version
2.4.0
Deps
0
Vulns
0
Weekly
0
Stars
383

hashmap

A small HashMap class for JavaScript — any key type, stable API since 2012, rewritten for 3.0.

Works in Node.js (14+) and the browser. ESM, CommonJS, TypeScript types, and an IIFE build included.

NPM

npm install hashmap
import HashMap from 'hashmap'
// or
const HashMap = require('hashmap')

Why this exists

Native Map didn't exist when this library was created. It does now — and for most new code, Map is the right default.

hashmap is still worth reaching for when you need more than Map gives you:

hashmap Map WeakMap
Any key type (null, numbers, strings, objects, …) yes yes objects only
Object keys by identity yes yes yes
Iterate all entries / .size yes yes no
Value-based equality for Date, RegExp, arrays yes no no
Reverse lookup (.search(value)) yes no no
Method chaining on mutators yes partial no

Use hashmap when:

  • You need custom key equality — two Date objects with the same timestamp, two /foo/ regexes, arrays compared element-wise.
  • You need .search() — find the key for a value.
  • You're maintaining legacy code that already depends on this API (plugin systems, protobuf registries, object-key pools, etc.).
  • You want a stable, zero-dependency map that behaves the same in Node and the browser.

Use native Map when: string/number/symbol keys with === equality is enough. That's most apps.

Use WeakMap when: keys are objects and you want them garbage-collected when nothing else references them. You can't iterate a WeakMap.


Quick start

const map = new HashMap()

map.set('1', 'string one')
map.set(1, 'number one')
map.get('1') // 'string one'
map.get(1)   // 'number one'

const a = {}
const b = {}
map.set(a, 'first')
map.set(b, 'second')
map.get(a) // 'first' — object identity, not stringification
Method chaining
new HashMap()
  .set(1, 'one')
  .set(2, 'two')
  .forEach((value, key) => console.log(key, value))
Iteration
map.forEach((value, key) => { /* … */ })

for (const { key, value } of map) {
  console.log(key, value)
}
Reverse lookup
map.set('id', 42)
map.search(42) // 'id'

API

Constructor
  • new HashMap() — empty map
  • new HashMap(other) — copy from another HashMap
  • new HashMap([['k1', 'v1'], ['k2', 'v2']]) — from pairs array
  • new HashMap(k1, v1, k2, v2, …) — from arguments
Methods
Method Description
get(key) Value for key, or undefined
set(key, value) Store a pair (chainable)
has(key) Whether key exists
delete(key) Remove by key (chainable)
search(value) Key for value, or null
clear() Remove all entries (chainable)
forEach(fn, ctx?) Iterate (value, key) (chainable)
keys() / values() / entries() Arrays of keys, values, or [key, value] pairs
clone() Shallow copy as a new HashMap
copy(other) Copy entries from other into this map (chainable)
multi(k1, v1, …) Set several pairs at once (chainable)
size Number of entries

Deprecated aliases kept for compatibility: remove()delete(), count()size, type().

TypeScript

Types ship with the package. Generics work as expected:

import HashMap from 'hashmap'

const cache = new HashMap<string, number>()
cache.set('answer', 42)

Browser

For a script tag without a bundler, use the IIFE build:

<script src="node_modules/hashmap/dist/hashmap.iife.js"></script>
<script>
  const map = new HashMap()
  map.set(document.body, 'root')
</script>

Benchmarks

3.0 rewrote the internals (numeric hashing, flat entry storage, eager Map index, cached entry hashes). Measured on Node 24, ~250 ms per benchmark, string keys unless noted. Run locally:

npm run benchmark
npm run benchmark -- -o tmp/current.json --compare tmp/benchmark-baseline.json
vs 2.4.0
Operation 2.4.0 3.0.0 Change
set 226K 266K 1.2×
get 224K 298K 1.3×
has 237K 268K 1.1×
delete 210K 264K 1.3×
set (replace existing key) 7K 193K 26×
get (map with 1024 entries) 10K 273K 27×
forEach (1024 entries) 29K 1.7M 60×
keys (1024 entries) 26K 722K 28×
clone (1024 entries) 11K 19K 1.7×
copy (1024 entries) 12K 19K 1.6×
set after delete (1024 entries) 238K 91K 0.4×

Summary: 18 of 20 benchmarks faster than 2.4.0. Biggest wins: replacing/updating keys, iteration, and clone/copy. Remaining gaps: burst inserts into an empty map and delete-then-set on large maps.

Values are ops/sec (higher is better). Native Map is faster on plain get with string keys — hashmap trades that for custom equality, .search(), and the legacy API.


Development

npm test        # types + unit tests
npm run build   # dist (esm, cjs, iife, dts)
npm run lint

License

MIT Ariel Flesler

Keywords