简体   繁体   English

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

[英]mixing constructor and apply traps on the Javascript Proxy object

I have a class that I'd like to apply a proxy to, observing method calls and constructor calls: 我有一个类,我想应用代理,观察方法调用和构造函数调用:

Calculator.js Calculator.js

class Calc {
  constructor(){}

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

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

module.exports = Calc;

index.js 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));

When this is called, I would expect for the output to be: 当调用它时,我希望输出为:

Object instantiated 对象实例化

Method called 方法叫做

however, the apply is not being called, I assume that this is because I am attaching the Proxy to the Calculator class, but not the instantiated object, and so doesn't know about the apply trap. 但是,apply没有被调用,我认为这是因为我将Proxy附加到Calculator类,而不是实例化的对象,所以不知道apply trap。

How can i build an all encompassing Proxy to "observe" on method calls and constructor calls. 如何在方法调用和构造函数调用上构建一个包含所有代理的“观察”代理。

I assume that this is because I am attaching the Proxy to the Calculator class, but not the instantiated object, and so doesn't know about the apply trap. 我假设这是因为我将Proxy附加到Calculator类,而不是实例化的对象,因此不知道apply trap。

You are totally right, proxies act upon objects, so it won't call apply unless a function property of the Calculator class is called, as follows: 你是完全正确的,代理对对象起作用,所以除非调用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(); 

With that clear, what you could do to wrap an instance of Calculator with a proxy could be: 有了这个清楚,你可以用一个代理包装Calculator实例的方法是:

  1. Have the class proxy to proxify instances on construct : 让类代理在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. Have a factory function in the Calculator class in order to create proxified instances: Calculator类中有一个工厂函数,以便创建代理实例:

 const CalculatorInstanceHandler = { apply(target, thisArg, args) { return target(...args); } }; class Calculator { static getNewCalculator() { const instance = new Calculator(); return new Proxy(instance, CalculatorInstanceHandler); } } 

Instead of using handler.apply() on the class, modify what handler.construct() returns, adding a Proxy to that instead. 不要在类上使用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)); 

There's 2 proxies in play here: 这里有2个代理人:

  • A proxy to observe constructor calls, and wrap any instances created by that constructor with... 用于观察构造函数调用的代理,并使用该构造函数创建的任何实例包装...
  • ...a proxy to observe property accesses, and log when those properties are functions. ...一个观察属性访问的代理,并在这些属性是函数时记录。 It will also wrap any functions, so it can observe calls to that function. 它还将包装任何函数,因此它可以观察对该函数的调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM