How to properly extend ES6 Map

It is unclear whether it's allowed by specification

It is. Since ES6, all builtin types are extensible using class syntax

It is unclear what browser/node.js versions support it

They need to support ES6 classes and Map natively. Using a transpiler will usually break it.

1) Subclass it. That I've done, and it seems like it works.

Yes, that is the correct approach.

a lot of articles on the Internet state that you can run into troubles with extending built-in objects. Most are early 2016, and now is late 2017, testing in Chrome 61.

I dunno, the major reference http://perfectionkills.com/extending-native-builtins/ is from 2011. And these articles meant a different thing by "extending builtins": amending their prototype objects with custom objects, e.g. Map.prototype.getWithDefault = function(…) { … };. They do not refer to class … extends ….

Make a wrapper object

This should be fine as well. I don't think you necessarily need your instances to be instanceof Map, if you do you'd have to follow the Liskov substitution principle. Not all "extensions" of a key-value collection would fit that.

3) Use ES6 Proxy - it is unadvisable to apply Proxy to some built-in types.

Indeed, this doesn't work or is at least cumbersome.


You can use your first approach using a class which extends Map.

For example, the below is an implementation of queues (FIFO structures) extending Map, which allows you to manage queues in JavaScript with a O(1) time complexity for both insertions and removals:

class MyQueue extends Map {
  constructor() {
    super();
    this.insertionIndex = 0;
    this.removalIndex = 0;
  }

  queue(element) {
    this.set(this.insertionIndex, element);
    this.insertionIndex++;
  }

  dequeue() {
    const el = this.get(this.removalIndex);
    this.delete(this.removalIndex);
    if (el) {
      this.removalIndex++;
    }
    return el;
  }
}

const q = new MyQueue();
q.queue(1);
q.queue(2);
console.log(q.dequeue());
console.log(q.dequeue());
q.queue(3);
console.log(q.dequeue());
console.log(q.dequeue()); // now is empty so dequeue will return undefined with no errors
q.queue(4);
console.log(q.dequeue());