Home > Back-end >  How to trap ES6 getter with ES6 proxy?
How to trap ES6 getter with ES6 proxy?

Time:12-06

I use a proxy to monitor all property accesses on a class's instances, like in the following example:

class Person {
  public ageNow: number;

  public constructor(ageNow: number) {
    this.ageNow = ageNow;

    const proxy = new Proxy(this, {
      get: (target, property) => {
        console.log(property);
        return target[property as keyof typeof target];
      },
    });
    return proxy;
  }

  public ageIn10Years1() {return this.ageNow   10;}
  public get ageIn10Years2() {return this.ageNow   10;}
}

Now when I do e.g.

const peter = new Person(18);
console.log(peter.ageIn10Years1());

it prints 'ageInYears1', 'ageNow' and 28 (in that order), as I expect.

However, when I do

console.log(peter.ageIn10Years2);

i.e. use a getter, it also prints 'ageInYears2' and 28 but no longer 'ageNow', although that property is clearly accessed.

Why is that and how can I fix it?

CodePudding user response:

The getter use the original object not the proxy that you created

One solution is to call the getter function on the proxy.


class Person {
  public ageNow: number;

  public constructor(ageNow: number) {
    this.ageNow = ageNow;
    const proxy = new Proxy(this, {
      get: (target, property) => {
        const descriptor = Object.getOwnPropertyDescriptor(Person.prototype, property);
        if (descriptor && typeof descriptor.get === 'function') {
            console.log("calling",property);
          return descriptor.get.call(proxy);
        } else {
          console.log(property);
          return target[property as keyof typeof target];
        }
      },
    });
    return proxy;
  }

  public ageIn10Years1() {return this.ageNow   10;}
  public get ageIn10Years2() {return this.ageNow   10;}
}


const peter = new Person(18);
console.log(peter.ageIn10Years1());
console.log(peter.ageIn10Years2);

CodePudding user response:

The problem is linked to how this works.

In the first case you're calling your method like this: peter.ageIn10Years1() so this is equal to peter, meaning the proxy. That's why every value is correctly proxified.

You can verify that that binding your ageIn10Year1 method:

class Person {
  constructor(ageNow) {
    this.ageNow = ageNow;

    this.ageIn10Years1 = this.ageIn10Years1.bind(this);

    const proxy = new Proxy(this, {
      get(target, property, receiver) {
        console.log(property)
        return target[property];
      },
    });
    return proxy;
  }

  ageIn10Years1() {
    return this.ageNow   10;
  }
  getAgeIn10Years2() {
    return this.ageNow   10;
  }
}

const peter = new Person(18);
console.log(peter.ageIn10Years1());

Now, this call work the same as the other.


In the second case, you're using a getter so this is not dynamically bounded and represent the initial object.

Maybe the simplest way to solve this problem would be to avoid using getters.

  • Related