5

Consider the following two snippets (from this jsperf entry):

let val = 0;
for(let i of indices) {
  val += map.get(i);
}
// ---
let val = 0;
for(let i of indices) {
  val += obj[i];
}

Here, map is a Map, obj is a plain old JavaScript object (let obj = {}), and indices is an array of random indices. Both obj and map have been pre-populated with data so the lookups actually return data. Check out the jsperf for the full code.

Question:

Why does the plain old javascript object out-perform the Map by a factor of 5+? Is this simply because as of writing, Maps are still very new and un-optimised? Or is there some overhead in Map lookups that will always keep it from being as fast as a POJO?

If it's just not optimised yet, can we expect it to be faster than a POJO for random lookups eventually? Why? Why not?

Community
  • 1
  • 1
  • 1
    I suspect it's because of the method call overhead. Also, you are abusing the collection(s) as an array, storing only integer indices. For which property access is super-optimised. Try with some type of key. – Bergi Jun 02 '17 at 05:23
  • @Bergi fixed the array (though to be clear, it's not relevant to this question) cheers The comparison that this question is referring to is POJO vs Map lookup speed. Are you saying that the map might not be as optimised as the POJO for integer indices? Or was that just a side thought and you're saying it's all (most likely) due to method call overhead? –  Jun 02 '17 at 05:33
  • 2
    I'm guessing it's both. You might also try to simulate the overhead by doing `obj = {get(p) { return this[p]; }};` and calling `obj.get(i)`, but [microbenchmarks easily fool us](http://mrale.ph/talks/goto2015/#/71). – Bergi Jun 02 '17 at 05:46
  • Didn't see your edit initially. Tried with a string key and added in the great `obj.get(i)` suggestion and it looks like you're right! https://jsperf.com/map-vs-pojo-lookups So the initial conundrum was a combination of POJO being optimised under the hood for integers (basically gets converted into an array), and the method call overhead. Feel free to post an answer with a link to that jsperf. Thanks for your help! –  Jun 02 '17 at 06:00

1 Answers1

4

Thanks to @Bergi for this answer.

The reason the plain JavaScript object performed so well in the initial jsperf compared to the Map is because under the hood a JS engine can see that we're using the object like it's an array (consecutive integer keys), so it "assumes" that it's an array and can make a bunch of optimisations based on that. Not so with the Map.

But the Map has a further disadvantage in that it requires a method call (map.get(p)), as opposed to a direct property lookup (obj[p]). This hasn't been (can't be?) optimised away as shown by this jsperf: http://jsperf.com/map-vs-pojo-lookups