Jarede
Jarede

Reputation: 3498

reflection appears to be losing this

I'm trying to build an AOP logger for my classes... I'm having an issue where when i reflect back to the targeted function, the function loses access to this

so my AOP kinda looks like this

AOP.js

class AOP {
  constructor() {

  }
  static ClassHandler(obj) {
    const InstanceHandler = {
      get(target, prop, receiver) {
        console.log(target.constructor.name);
        const origMethod = target[prop];
        return function (...args) {
          // let result = Reflect.apply(origMethod, this, args)
          let result = Reflect.get(target, prop, receiver)
          result = Reflect.apply(result, this, args);
          console.log(prop + JSON.stringify(args)
              + ' -> ' + JSON.stringify(result));
          return result;
        };
      },
      apply(target, thisArg, argumentsList) {
        console.log('actually applied');
      }
    }

    const handler = {
      construct(target, args) {
        console.log(`${target.name} instantiated`);
        console.log(args);
        const instance = Reflect.construct(...arguments);
        return new Proxy(instance, InstanceHandler);
      }
    }

    return new Proxy(obj, handler);
  }
}

module.exports = AOP;

A singleton

OtherClass.js

class OtherClass {
  constructor() {
    this._blah = 'this is a shoutout';
  }

  shoutOut() {
    console.log(this._blah);
  }
}

module.exports = new OtherClass();

and a class which requires the singleton

CalculatorDI.js

class Calculator {
  constructor(otherClass) {
    this.otherClass = otherClass;
  }

  add(a, b) {
    this.otherClass.shoutOut();
    return a+b;
  }

  minus(a, b) {
    return a-b;
  }
}

module.exports = Calculator;

bringing it all together like this:

const AOP = require('./src/aspects/AOP');
const Calculator = AOP.ClassHandler(require('./src/CalculatorDI'));
const otherClass = require('./src/OtherClass');
const calculator = new Calculator(otherClass);

calculator.add(1,1);

When running this, I get the error:

TypeError: this.otherClass.shoutOut is not a function

Upvotes: 2

Views: 99

Answers (1)

Bergi
Bergi

Reputation: 665286

Your problem is that your proxy always returns a function, for any property that is accessed, including this.otherClass. You will need to use

const instanceHandler = {
  get(target, prop, receiver) {
    console.log(target.constructor.name);
    const orig = Reflect.get(target, prop, receiver);
    if (typeof orig == "function") {
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      return function (...args) {
        const result = orig.apply(this, args);
        console.log(prop + JSON.stringify(args) + ' -> ' + JSON.stringify(result));
        return result;
      };
    } else {
      return orig;
    }
  }
};

Also notice that you don't need an apply trap in the instanceHandler, as none of your instances is a function.

Upvotes: 1

Related Questions