Nathan Ridley
Nathan Ridley

Reputation: 34396

Observing changes to ES6 Maps and Sets

Is there any way to observe additions to and removals from ES6 Maps and Sets? Object.observe doesn't work because it is only applies to direct properties of the observed object. Hypothetically the size property could be observed, but no indication would be provided of exactly what has changed. Another idea would be to replace the object's set and get functions with proxified versions. Is there a better way? If not, I'm surprised that nobody thought of this when the proposals were being written for ES6.

Upvotes: 5

Views: 944

Answers (2)

Kirill A. Khalitov
Kirill A. Khalitov

Reputation: 1265

Subclassing for Set/Map is not working at the moment. How about this method (just hasty example)?

//ECMAScript 2015
class XMap
{
  constructor(iterable, observer = null)
  {
    this._map      = new Map(iterable);
    this._observer = observer;
    this._changes  = {};
  }
  set(key, value)
  {
    this._changes.prev = this._map.get(key);
    this._changes.new  = value;
    this._map.set(key, value);

    if(this._observer !== null)
    {
      this._observer(this._changes);
    }
  }
  get(key)
  {
    return this._map.get(key); 
  }
}

var m = new XMap([[0, 1]], changes => console.log(changes));

m.set(0,5);  // console: Object {prev: 1, new: 5}
m.set(0,15); // console: Object {prev: 5, new: 15}

Upvotes: 2

Domenic
Domenic

Reputation: 112827

No, there is no way to do this with a vanilla Map/Set. In general observation of object properties alone is controversial (that is why Object.observe is only a proposal, and not an accepted part of the spec). Observing private state, like the internals of a Map or Set (or Date or Promise, for that matter), is definitely not on the table.

Note also that since size is a getter, not a data property, Object.observe will not notify you of changes to it.

As you mention, you can achieve such "observation" via collaboration between the mutator and the observer. You could either do this with a normal Map/Set plus a side-channel (e.g. a function returning a { Map, EventEmitter } object), or via a subclass tailored for the purpose, or a specific instance created for that purpose.

Upvotes: 4

Related Questions