7

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

计算器.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 没有被调用,我认为这是因为我将代理附加到 Calculator 类,而不是实例化的对象,因此不知道apply陷阱。

我如何构建一个包罗万象的代理来“观察”方法调用和构造函数调用。

4

2 回答 2

5

我认为这是因为我将代理附加到计算器类,而不是实例化对象,因此不知道应用陷阱。

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

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

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以创建代理实例:

const CalculatorInstanceHandler = {
  apply(target, thisArg, args) {
    return target(...args);
  }
};

class Calculator {

  static getNewCalculator() {
    const instance = new Calculator();

    return new Proxy(instance, CalculatorInstanceHandler);

  }
}

于 2018-06-13T17:15:56.997 回答
2

不要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 个代理:

  • 观察构造函数调用的代理,并用...包装由该构造函数创建的任何实例
  • ...观察属性访问的代理,并在这些属性是函数时进行记录。它还将包装任何函数,因此它可以观察对该函数的调用。
于 2018-06-13T17:50:21.650 回答