Map.prototype.has()

The clean existence check that objects never quite managed. There is no prototype to confuse it, no hasOwnProperty to be shadowed, and no __proto__ hazard.

Map methodES2015Live demo
Common call
map.has(key)
Returns
boolean
Replaces
Object.hasOwn, and the in operator
Watch out
same no-coercion rule — 1 is not "1"
map.has(keykey — The key to test, matched by SameValueZero. NaN is found; 0 and -0 are the same key.type: any · required)
→ boolean

Demo

Live evaluation
Try:
Inputs
jsonstringJSON pairs, e.g. [["a",1]]
kstringkey to test
Output
new Map(JSON.parse('[["a",1]]')).has('a')
true

A key holding null or undefined still counts as present — existence and value are separate questions here, which is exactly what get cannot tell you. The last two cases are where Map beats an object outright: 'toString' and '__proto__' are not special. On a plain object, 'toString' in obj is true before you set anything, and assigning __proto__ can replace the prototype. A Map has no prototype chain for its entries, so both are simply absent keys.

Parameters

NameTypeRequiredDescription
keyanyyesThe key to test, matched by SameValueZero. NaN is found; 0 and -0 are the same key.

Return value

boolean — True if an entry with that key exists, whatever its value. Unaffected by the prototype chain, because a Map has no inherited entries.

Common patterns

Existence without reading
Works even when values may be undefined.
if (!map.has(id)) return notFound();
A safe dictionary for untrusted keys
No key name is dangerous.
const counts = new Map();
counts.set(userInput, 1);
Get-or-create
has, then set, then get.
if (!m.has(k)) m.set(k, []);
m.get(k).push(x);

Examples

1. Present
new Map([["a", 1]]).has("a")
Returns
true
2. Absent
new Map().has("a")
Returns
false
3. undefined value
new Map([["a", undefined]]).has("a")
Returns
true
4. get cannot tell
new Map([["a", undefined]]).get("a")
Returns
undefined
5. No inherited keys
new Map().has("toString")
Returns
false
6. An object has it
"toString" in {}
Returns
true

Pitfalls

1. No coercion, as everywhere in Map
has(1) and has("1") ask about different keys. Ids that arrive as strings from a URL or JSON will not match a Map built with numbers, and the failure is a silent false rather than an error.
Misses
new Map([[1, "x"]]).has("1")
false
Normalise
new Map([[1, "x"]]).has(Number("1"))
true
2. It is not the in operator
in on a Map instance tests for a PROPERTY of the Map object, not an entry. "a" in map is false even when the entry exists, and "size" in map is true — neither answer is about your data.
Wrong question
const m = new Map([["a", 1]]);
"a" in m
false
Use has
m.has("a")
true
3. Object keys still need the same reference
has is subject to the identity rule like get. A structurally identical object is a different key, so has({id: 1}) on a Map keyed by an equal-looking object is false.
Different object
new Map([[{id: 1}, "x"]]).has({id: 1})
false
Same reference
const k = {id: 1};
new Map([[k, "x"]]).has(k)
true
4. has-then-get is two lookups
Correct and readable, and twice the hash work. Only worth avoiding in a genuinely hot loop, where a single get plus an undefined check does the job if you never store undefined.
Two lookups
if (m.has(k)) use(m.get(k));
works
One
const v = m.get(k);
if (v !== undefined) use(v);
if undefined is not a value

When to use

Use it
  • Testing existence when values may be undefined or null
  • Dictionaries keyed by untrusted strings, where object keys would be unsafe
  • The get-or-create accumulator pattern
  • Replacing Object.hasOwn on data that is really a keyed collection
Reach for something else
  • You need the value anyway → get, and check the result
  • Keys are a fixed set of known strings → an object is simpler
  • You want to know about inherited properties → that concept does not apply here

Notes

Complexity
O(1) average
Return
A boolean; nothing is allocated
CPython impl
V8: Builtins-map-has
Memory
No allocation
Thread-safe
Single-threaded; the Map is only read

FAQ

Because a Map has no prototype chain for its entries. On an object you must use Object.hasOwn to avoid inherited properties, and a key named __proto__ can replace the prototype instead of storing a value. A Map treats every key as ordinary data.

new Map().has("toString");   // false
"toString" in {};            // true

History

ES2015
Map added with has alongside get, set and delete.