【问题标题】:Intercept function calls in javascript拦截javascript中的函数调用
【发布时间】:2019-01-13 18:21:24
【问题描述】:

PHP 中的 __call 魔术方法等效于什么?

我的印象是 Proxy 可以做到这一点,但它不能。

class MyClass{
  constructor(){
    return new Proxy(this, {
      apply: function(target, thisArg, args){
        console.log('call', thisArg, args);
        return 'test';
      },

      get: function(target, prop){
        console.log('get', prop, arguments);
      }


    });

  }

}

var inst = new MyClass();
console.log(inst.foo(123));

get 似乎工作,因为我看到“get foo”,但 apply 没有。我得到的不是函数错误。

【问题讨论】:

标签: javascript node.js function proxy


【解决方案1】:

apply 实际上处理对对象本身的函数调用,即如果你这样做new Proxy(someFunction, { apply: ... })apply 将在调用someFunction 之前被调用。

没有什么可以捕获对属性的调用,因为这将是多余的——get 已经在返回属性时进行了处理。您可以简单地返回一个函数,然后在调用时产生一些调试输出。

class MyClass{
  constructor(){
    return new Proxy(this, {
      get: function(target, prop) {
        return function() {
          console.log('function call', prop, arguments);
          return 42;
        };
      }
    });
  }
}

var inst = new MyClass();
console.log(inst.foo(123));

【讨论】:

  • 我不认为这是一个完整的解决方案。您返回了一个静态值。您需要在get 中使用apply 来计算原始函数的结果。
  • @BadisMerabet 我确信 OP 可以修改函数以满足他们的需要。然而,这个问题类似于 PHP 中的__call,它用于解析对象的不存在函数,即没有“原始函数”可以调用。 Proxy 的默认/预期行为是 well-documented already
  • 感谢您澄清这一点,这是有道理的。我仍然对拦截对一段代码或软件中不存在的函数的调用的目标或好处感兴趣吗?
  • @BadisMerabet 我知道这种“魔术”(类似于某些语言中的宏,以及其他语言中的运行时反射)可用于实现例如ORM 系统,其中可以为一对多关系动态生成方法。我能想到的其他一些用途——一个具有延迟加载的模块/函数的库,具有(太多)许多具有给定模式的函数的库(例如几何库——addPoint2DaddPoint3D,...)。有很多应用程序,也许它们并不总是表示“好”代码,但这毕竟是 Javascript。 :)
【解决方案2】:

这是实现您所要求的另一种方式。

class MyClass{
  constructor(){
     return new Proxy(this, {
        get(target, propKey, receiver) {
            const origMethod = target[propKey];
            return function (...args) {
                let result = origMethod.apply(this, args);
                console.log(propKey + JSON.stringify(args)
                    + ' -> ' + JSON.stringify(result));
                return result;
            };
        }
    });
  }
  
foo = (x) => {
  return x + 1;
};

}

var inst = new MyClass();
console.log(inst.foo(123));

【讨论】:

  • 太棒了!这会拦截对对象的所有方法调用,即使方法实际上并不存在。
【解决方案3】:

是的,Proxy 可以做到这一点,但即使在捕获方法时,您也必须使用 Proxy 的get

那我这里也执行你的真实方法,不知道你要不要mock。

class MyClass {
  constructor() {
    return new Proxy(this, {
      get(target, prop, receiver) {
        if (typeof target[prop] !== "function") {
          return "etcetcetc";
        }
        return function(...args) {
          console.log('call', args);
          return target[prop]();
        };
      }
    });
  }

  foo() {
    console.log('I am foo!');
  }
}

var inst = new MyClass();
inst.foo(123);

如您所见,如果您正在调用您实例的方法,我会拦截它,然后返回您原来的方法执行。

如果您正在访问实例的属性,我将始终返回一个模拟字符串。

然后当然可以用你想要的行为来改变它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-08-25
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-23
    相关资源
    最近更新 更多