The use of Map VS. Objects


#1

I have run into many situations where what I need is a Map. When I do I always have the same question that needs to be answered: Should I polyfill Map or attempt to use a POJO as a Map? Ember has a private implementation of Map which would be nice but it is private.

For production code I’m looking for

  • maintainability (will this be supported as the app upgrades)
  • readability (how easy is it to grok its usage)
  • developer ergonomics (how easy is it to work with)

I’ve narrowed down the API to the following two options: JavaScript Map via a polyfill, build my own via two denominational arrays, or manage it via a POJO. The later two are supported by all browsers and do not need a polyfill but does introduce some complexity. It is more obtuse to use Object.keys then it is to simply iterate over the Map (for (let [ key, value ] of myMap)) and less performent to force iteration to get a single value with two-dimentional arrays.

My questions are:

  1. Is it worth forcing a babel polyfill for the use of the built in Map?
  2. Is the private ember Map worth looking into if the keys are not strings?
  3. If the keys are always strings is it worth using Map at all just for the iteration and nice API or just manipulate a POJO with pojo[name], pojo[name] =, delete pojo[name], and Object.keys(pojo)?

#2

For reference here is an example POJO implementation:

class Hash {
  constructor(entries = []) {
    this.hash = {};
    entries.forEach(entry => this.set(...entry));
  }
  has(key) { return !!this.hash[key]; }
  set(key, value) { this.hash[key] = value; }
  get(key) { return this.hash[key]; }
  delete(key) { delete this.hash[key]; }
  clear() { this.hash = {}; }
  keys() { return Object.keys(this.hash); }
  values() { return this.keys().map(k => this.hash[k]); }
  entries() { return this.keys().map(k => [k, this.hash[k]]); }
  forEach(cb, ctx = this) { this.entries().forEach(x => cb.call(cb, ctx, x[1], x[0], this)); }
  [Symbol.iterator]* () { yield* this.entries(); }
  get size() { return this.keys().length; }
}

It means string only keys and loss of insertion order but in my cases these don’t matter. Thoughts?


#3

So it turns out that that neither Map nor my own hash based implementations are KVO-compliant. Either I need to do some fancy EmberObject magic or simply use a two-dimensional array and take the performance hit.