Decay42
Decay42

Reputation: 882

Getter for arbitrary property of object

I have a class that looks like this

export default class {
  constructor () {
    this.store = {}
  }

  setX (x, y) {
    this.store[x] = y
  }
}

How would I define a getter on this.store to return 0 when getting an undefined value?

Let me give an example:

setX('a', 1) would set this.store['a'] to 1

then this.store['a'] would return 1, as expected.

But this.store['b'] would return undefined, but I want the getter to return 0 instead (and maybe call setX('b', 0), not sure yet).

I know I can use Object.defineProperty to define a custom getter, I just can't wrap my head around how to access an arbitrary, not yet defined property of the store object.

Is this at all possible or do I have to use a work-around like this?

getX (x) {
  return this.store[x] || 0
}

I would like to avoid that, because this.store[x] seems so much cleaner.

Upvotes: 6

Views: 711

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1075517

How would I define a getter on this.store to return 0 when getting an undefined value?

Unless you can anticipate all possible property names you want to support and define getters for them, to do that you need a Proxy with a get trap, which is new as of ES2015 (and cannot be polyfilled). Proxies are expensive in performance terms, use them only when you really need them.

Example:

class Example {
  constructor () {
    this.store = new Proxy({}, {
      get(target, property) {
        return property in target ? target[property] : 0;
      }
    });
  }

  setX (x, y) {
    this.store[x] = y;
  }
}

const e = new Example();
console.log("Setting a");
e.setX("a", "foo");
console.log("a = " + e.store.a);
console.log("b = " + e.store.b);

Of course, if you make store private, you could enforce access only through a getX method on the object, which would avoid the use of a proxy at the expense of defining setX and getX on a per-instance basis (for now, private data is coming):

class Example {
  constructor () {
    const store = {};
    this.setX = (x, y) => {
      store[x] = y;
    };
    this.getX = x => {
      return x in store ? store[x] : 0;
    };
  }
}

const e = new Example();
console.log("Setting a");
e.setX("a", "foo");
console.log("a = " + e.getX("a"));
console.log("b = " + e.getX("b"));

Upvotes: 8

Related Questions