Search code examples
javascriptes6-proxy

How to create a trap for properties on a constructible JavaScript object


Proxy has a trap for new operator, which in theory should allow us to create Proxies that pass constructor arguments through to the target object. Example of how it works looks like this:

function monster1(disposition) {
  this.disposition = disposition;
}

const handler1 = {
  construct(target, args) {
    console.log('monster1 constructor called');
    // expected output: "monster1 constructor called"

    return new target(...args);
  },
  
  get(...args) {
    console.info('get trap triggered!')
  }
};

const proxy1 = new Proxy(monster1, handler1);

const instance = new proxy1('fierce')

console.log(instance.disposition);
// expected output: "fierce"

console.log(instance.unknownProp);
// expected output: "get trap triggered!" <-- doesn't happen

This works perfectly. Except that instance.unknownProp now doesn't trigger get trap anymore. How do I intercept properties now?


Solution

  • Inside Construct you have return new target(...args);. That creates a new JS object, without any proxies set.

    You should set an additional proxy on the newly created object to intercept property access there.

    Like this:

    function monster1(disposition) {
      this.disposition = disposition;
    }
    
    const handler1 = {
      construct(target, args) {
        console.log('monster1 constructor called');
        // expected output: "monster1 constructor called"
    
        const obj = new target(...args);
    
        // Return a Proxy instead of object. 
        // We may use the same handler1 here, or we can
        // create another handler with `get`. Both work,.
        return new Proxy(obj, handler1);
      },
      
      get(...args) {
        console.log('get trap triggered!')
        return Reflect.get(...args);
      }
    };
    
    const proxy1 = new Proxy(monster1, handler1);
    
    const instance = new proxy1('fierce')
    
    console.log(instance.disposition);
    // expected output: "get trap triggered!"
    // expected output: "fierce"
    
    console.log(instance.unknownProp);
    // expected output: "get trap triggered!"