jsguides

Map.prototype.has()

map.has(key)

The has() method returns a boolean indicating whether a Map contains a specific key. Key comparison uses the SameValueZero algorithm — the same rule the Map uses when storing entries. This means object keys are compared by reference, not by value, and NaN is treated as equal to itself.

Unlike checking property existence on a plain object with in or hasOwnProperty, has() only looks at the Map’s own entries and never traverses a prototype chain.

Syntax

map.has(key)

Parameters

ParameterTypeDescription
keyanyThe key to check for in the Map

Return value

true if the key exists in the Map, false otherwise. Unlike get(), which returns undefined for both missing keys and keys set to undefined, the return value of has() unambiguously tells you whether the key was stored.

Examples

Basic usage

const userRoles = new Map();
userRoles.set('alice', 'admin');
userRoles.set('bob', 'editor');

console.log(userRoles.has('alice'));
// true

console.log(userRoles.has('unknown'));
// false

With string keys, has() behaves like a straightforward membership check. Object keys introduce an important twist: the SameValueZero algorithm compares by identity, not by structural equality. Two objects with the same shape are not the same key — only the exact object reference you originally used will match.

Using with object keys

const visits = new Map();

const page1 = { path: '/home', lang: 'en' };
visits.set(page1, 1500);

console.log(visits.has(page1));
// true

// Different object reference - not found
console.log(visits.has({ path: '/home', lang: 'en' }));
// false

Two objects with identical structure are not the same key. The Map stores the original object reference and compares by identity. This matters when you use has() to check for object-keyed entries: you must hold a reference to the original object that was used as the key, because a freshly-created object with the same properties will not match.

Conditional value retrieval

const cache = new Map();

function getCached(key) {
  if (!cache.has(key)) {
    return null;
  }
  return cache.get(key);
}

cache.set('users', ['alice', 'bob']);
console.log(getCached('users')); // ['alice', 'bob']
console.log(getCached('missing')); // null

Checking with has() before calling get() is the safest pattern when undefined is a valid stored value, because get() returns undefined for both missing keys and keys explicitly set to undefined. The same pattern applies when you need to confirm a key’s presence before performing a side effect, such as logging or deleting the entry.

Before delete operation

const queue = new Map([['job1', { status: 'running' }]]);

function cancelJob(jobId) {
  if (!queue.has(jobId)) {
    console.log(`Job ${jobId} not found`);
    return false;
  }
  
  queue.delete(jobId);
  console.log(`Job ${jobId} cancelled`);
  return true;
}

cancelJob('job1'); // Job job1 cancelled
cancelJob('job2'); // Job job2 not found

The previous examples show has() used for lookups. It is equally useful as a guard for mutation — checking before writing or deleting avoids accidental overwrites and keeps error messages precise. The following two patterns demonstrate these guards in practice.

Common patterns

Prevent overwriting existing entries

const registry = new Map();

function register(name, handler) {
  if (registry.has(name)) {
    throw new Error(`Handler ${name} already registered`);
  }
  registry.set(name, handler);
}

register('init', () => {});
register('init', () => {}); // Throws Error

The prevent-overwrite pattern above is useful for registries where duplicate keys are errors. When duplicates are allowed but you still need to know whether a lookup will succeed, has() works well as a log-before-access guard — confirming existence without modifying the map.

Key existence before access

const configs = new Map([
  ['production', { debug: false }],
  ['development', { debug: true }]
]);

function getConfig(env) {
  const exists = configs.has(env);
  console.log(`Config for ${env} exists: ${exists}`);
  return configs.get(env);
}

getConfig('production'); // Config for production exists: true
getConfig('staging'); // Config for staging exists: false

Comparing with plain objects

When working with a plain object you might check property existence with the in operator or Object.prototype.hasOwnProperty. Both have edge cases: in traverses the prototype chain and can match inherited properties, and hasOwnProperty can be shadowed by a property with the same name. Map.prototype.has() has neither issue — it only checks entries you explicitly added, and the method cannot be shadowed because you call it through the Map prototype, not as a property on the map itself.

const obj = {};
console.log('toString' in obj); // true — inherited from Object.prototype

const map = new Map();
console.log(map.has('toString')); // false — only checks map entries

Performance

has() runs in O(1) average time, the same as get() and set(). The underlying hash table means the lookup time does not increase as the Map grows. For large collections where you need to repeatedly check membership, a Map (or Set) is far more efficient than searching an array with includes() or find().

When has() is the right check

Map.prototype.has() is the right choice when the question is simply whether a key exists. That makes it a natural companion to get(), especially when undefined can be a real stored value. By checking existence first, you can tell the difference between “missing” and “present but empty” without relying on the return value of get().

It is also a good fit for cache lookups and registry-style data where keys are meant to be unique. In those cases, has() keeps the intent clear: you are asking about membership, not about the value itself. That distinction makes the code easier to follow and helps avoid accidental overwrites or mistaken fallback logic.

See Also