Avi L
Avi L

Reputation: 1708

Performance difference between Map.has vs Map.get

Is there any advantage to use Map.has() for checking if key exists in Map instead of using Map.get()? (Other than code readability reasons)

I checked ES2015 language specifications and both methods seems the same except the return value so I believe the performance is the same but maybe there are some other aspects I don't know of that could affect performance here.

Map.prototype.has ( key )

The following steps are taken:

Let M be the this value. If Type(M) is not Object, throw a TypeError exception. If M does not have a [[MapData]] internal slot, throw a TypeError exception. Let entries be the List that is the value of M’s [[MapData]] internal slot. Repeat for each Record {[[key]], [[value]]} p that is an element of entries, If p.[[key]] is not empty and SameValueZero(p.[[key]], key) is true, return true. Return false.

Map.prototype.has method specification

Map.prototype.get ( key )

The following steps are taken:

Let M be the this value. If Type(M) is not Object, throw a TypeError exception. If M does not have a [[MapData]] internal slot, throw a TypeError exception. Let entries be the List that is the value of M’s [[MapData]] internal slot. Repeat for each Record {[[key]], [[value]]} p that is an element of entries, If p.[[key]] is not empty and SameValueZero(p.[[key]], key) is true, return p.[[value]]. Return undefined.

Map.prototype.get method specification

Upvotes: 21

Views: 7047

Answers (2)

Nowan
Nowan

Reputation: 23

Let's say we're storing Objects into a Map :

const myMap = new Map(/* collection of objects */);`

In code samples, we can ofen see this :

function search(key) {
    if (myMap.has(key)) return null;
    let obj = myMap.get(key);
    return obj;
}

In case the key exists in the Map, we're searching for it 2 times : .has() then .get() !

The function can be optimized this way :

function search(key) {
    const obj = myMap.get(key);
    return obj || null;
}

But what if, instead of Objects we're storing primitive values ?

If the key exists, but its associated value is falsy (zero, false, empty string...), the last line will return null !

Of course, we could do this : return obj !== undefined ? obj : null

But we're lazy programmers, so let's use the nullish coalescing operator ??

function search(key) {
    const value = myMap.get(key);
    return value ?? null;
}

This will do the trick, wether we're dealing with Objects or primitive values :-)

Personnally, I never use the Map.prototype.has() method. Do you know examples where it could be useful ?

Upvotes: 0

CertainPerformance
CertainPerformance

Reputation: 371019

One reason why Map.has could be preferable would be if the key happens to exist, but the value is falsey. If you use Map.get, you'll also have to check whether the value === undefined (and even that does not guarantee that the key does not exist - the key may exist, but have a value of undefined):

// Not good enough:
const map = new Map();
map.set('foo', 0);
if (map.get('foo')) {
  console.log('Map has "foo" key');
}

// Better, but not foolproof:
const map = new Map();

map.set('foo', 0);
map.set('bar', undefined);

const valAtFoo = map.get('foo');
if (valAtFoo !== undefined) {
  console.log('Map has "foo" key');
}

// Incorrect:
const valAtBar = map.get('bar');
if (valAtBar !== undefined) {
  console.log('Map has "bar" key');
}

// Solution: use map.has instead of map.get
const map = new Map();
map.set('foo', 0);
map.set('bar', undefined);

if (map.has('foo')) {
  console.log('Map has "foo" key');
}

if (map.has('bar')) {
  console.log('Map has "bar" key');
}

You would use Map.has for the same reason that you would use Object.prototype.hasOwnProperty for checking whether an object has a certain property - using obj[prop] to check if the prop exists just isn't good enough in certain cases.

It's not an issue of performance - rather, it's because in some cases, there's just no other way. (.has is also more readable, though you said to ignore that part)

Upvotes: 27

Related Questions