混合构造函数并在Javascript代理对象上应用陷阱

时间:2018-06-13 16:52:19

标签: javascript ecmascript-6 proxy-pattern

我有一个类,我想应用代理,观察方法调用和构造函数调用:

Calculator.js

class Calc {
  constructor(){}

  add(a, b) {
    return a+b;
  }

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

module.exports = Calc;

index.js

const Calculator = require('./src/Calculator');

const CalculatorLogger = {
  construct: function(target, args, newTarget) {
      console.log('Object instantiated');
      return new target(...args);
  },
  apply: function(target, thisArg, argumentsList) {
      console.log('Method called');
  }
}
const LoggedCalculator = new Proxy(Calculator, CalculatorLogger);
const calculator = new LoggedCalculator();
console.log(calculator.add(1,2));

当调用它时,我希望输出为:

  

对象实例化

     

名为

的方法

然而,apply没有被调用,我认为这是因为我将Proxy附加到Calculator类,而不是实例化的对象,所以不知道apply陷阱。 / p>

如何在方法调用和构造函数调用上构建一个包含所有代理的“观察”。

2 个答案:

答案 0 :(得分:4)

  

我认为这是因为我将Proxy附加到Calculator类,而不是实例化对象,所以不知道apply trap。

你是完全正确的,代理操作对象,所以除非调用Calculator类的函数属性,否则它不会调用apply,如下所示:

class Calculator {
  constructor() {
    this.x = 1;
  }

  instanceFunction() {
    console.log('Instance function called');
  }

  static staticFun() {
    console.log('Static Function called');
  }

}

const calcHandler = {
  construct(target, args) {
    console.log('Calculator constructor called');
    return new target(...args);
  },
  apply: function(target, thisArg, argumentsList) {
    console.log('Function called');
    return target(...argumentsList);
  }
};

Calculator = new Proxy(Calculator, calcHandler);

Calculator.staticFun();

const obj = new Calculator();

obj.instanceFunction();

有了这个清楚,用代理包装Calculator实例的方法可能是:

  1. 让代理代理代理construct上的实例:
  2. const CalculatorInstanceHandler = {
      apply(target, thisArg, args) {
        console.log('Function called');
        return target(...args);
      }
    }
    
    const CalculatorClassHandler = {
      construct(target, args) {
        const instance = new target(...args);
        return new Proxy(instance, CalculatorInstanceHandler);
      }
    }

    1. Calculator课程中设置工厂功能,以便创建代理实例:
    2. const CalculatorInstanceHandler = {
        apply(target, thisArg, args) {
          return target(...args);
        }
      };
      
      class Calculator {
      
        static getNewCalculator() {
          const instance = new Calculator();
      
          return new Proxy(instance, CalculatorInstanceHandler);
      
        }
      }

答案 1 :(得分:1)

不要在类上使用handler.apply(),而是修改handler.construct()返回的内容,而不是向其中添加代理。



class originalClass {
  constructor() {
    this.c = 1;
  }
  add(a, b) {
    return a + b + this.c;
  }
}
const proxiedClass = new Proxy(originalClass, {
  construct(target, args) {
    console.log("constructor of originalClass called.");
    return new Proxy(new target(...args), {
      get(target, prop, receiver) {
        console.log(prop + " accessed on an instance of originalClass");
        const val = target[prop];
        if (typeof target[prop] === "function") {
          console.log(prop + " was a function");
          return function(...args) {
            console.log(prop + "() called");
            return val.apply(this, args);
          };
        } else {
          return val;
        }
      }
    });
  }
});
const proxiedInstance = new proxiedClass();
console.log(proxiedInstance.add(1, 2));




这里有2个代理:

  • 用于观察构造函数调用的代理,并使用...
  • 包装该构造函数创建的任何实例
  • ...观察属性访问的代理,并记录这些属性是否为函数。它还会包装任何函数,因此它可以观察对该函数的调用。