Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 748
Decay42 Avatar asked Dec 18 '17 12:12

Decay42


People also ask

What is a getter function?

The getter function is used to retrieve the variable value and the setter function is used to set the variable value. Remember: You can directly access public member variables, but private member variables are not accessible. Therefore, we need getter functions.

What is getter method in JavaScript?

In JavaScript, getter methods are used to access the properties of an object.

What is the difference between getter and setter in JavaScript?

Getters and setters allow us to define Object Accessors. The difference between them is that the former is used to get the property from the object whereas the latter is used to set a property in an object.

What does .get do in JavaScript?

The get syntax binds an object property to a function that will be called when that property is looked up.


1 Answers

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"));
like image 108
T.J. Crowder Avatar answered Sep 30 '22 07:09

T.J. Crowder