代理使用会混淆function.caller.name

时间:2017-03-16 10:53:54

标签: javascript oop proxy-classes

我正在尝试使用JavaScript模仿更类似于类的继承模型,但在尝试将其与JavaScript代理的想法混合时遇到了问题。

总而言之,在我的类类型的定义中,我有一个带有语义的函数 _super()“当子类B的实例上的方法X调用_super()时,调用父类A上的方法X“:

Class A
   .X() {...}
   ^
   |
   |
Class B
   .X() {..._super(); ...}

我依靠函数 .caller.name方法来获取调用方法的名称(在我们的示例中,“X”)。然后我在父类上调用它。

const Class = {
...
    _super: function _super(...args) {
      // Get a handle on the function in which this function is invoked:
      const callerMethod = _super.caller.name;
      ...
    },
...
};

这可以正常工作。当我在我的Class构造之上添加一个Proxy对象时,问题就出现了(我想要捕获一些方法调用)。

function traceMethodCalls(obj) {
  const handler = {
    get(target, propKey, receiver) {
      const origMethod = target[propKey];
      return function (...args) {
        // Do stuff
      };
    },
  };
  return new Proxy(obj, handler);
}

现在,_super()方法中的 function .caller是代理处理程序对象中的匿名函数(显然......),这会弄乱程序流。

我的问题:有没有办法规避这个?或者以不同的方式思考它?或者我是否必须完全放弃* .caller.name方法?

1 个答案:

答案 0 :(得分:0)

唯一想到的是检查堆栈以找到不是“_super”的第一件事。相当愚蠢的IMO,但在这里。

const Class = {

    _super: function _super(...args) {
        let callerMethod;

        let s = (new Error)
            .stack.split('\n')
            .slice(2);
        while (s.length && s[0].includes('_super'))
            s.shift();

        let m = (s[0] || '').match(/^\s*at\s\w+\.(\w+)/);
        callerMethod = m ? m[1] : null;
        console.log('super call [%s]', callerMethod)
    },

    foo: function () {
        this._super()
    }
};


function traceMethodCalls(obj) {
    const handler = {
        get(target, propKey, receiver) {
            const origMethod = target[propKey];
            let f = {
                [propKey]: function (...args) {
                    console.log('tracing', propKey)
                    origMethod.bind(this)()
                }
            };
            return f[propKey];
        },
    };
    return new Proxy(obj, handler);
}

obj = Object.create(Class)
obj.foo()
traced = traceMethodCalls(obj)
traced.foo()

一般来说,依靠功能名称总是危险的(想想uglifiers等)。我想可以公平地说,如果没有某种预编译,你就不能在js中工作super。注释