Javascript:知道调用了哪个对象函数

时间:2019-02-26 14:28:30

标签: javascript object

我想知道在javascript中调用任何对象函数时是否有通知的方法。

例如,我想执行以下操作:

如果我有这样的对象:

[[:space:]]

并添加一个侦听器(或其他用于跟踪对此对象执行的操作):

myObject = {
    functionOne: function(argumentOne) {
        // do some stuff
    },

    functionTwo: function() {
        // do some stuff
    }
}

当我打电话时:

myObject.addEventListener('onFunctionCall', functionHasBeenCalled);

使用有关被调用函数的信息触发的侦听器处理程序:

myObject.functionOne('hello');

控制台输出为:

functionHasBeenCalled(calledFunctionData) {
    console.log(calledFunctionData.functionName + ' has been called');
    console.log('with argument: ' + calledFunctionData.functionArgument);
}

也许有另一种方法可以实现此目的,而不是使用事件侦听器,但是我不知道。

谢谢!

2 个答案:

答案 0 :(得分:4)

一种方法可能是使用Proxy创建“跟踪”对象,在其中拦截任何方法调用:

function trackMethodCalls(obj) {
  const handler = {
    // anytime we do obj.someMethod
    // we actually return the interceptedMethod instead
    get(target, propKey, receiver) {
      
      const method = target[propKey];

      // we only do something special if we're working with a function
      // on the object. If the property isn't a function we can just return
      // it as normal.
      if (typeof method !== 'function') {
        return method;
      }

      return function interceptedMethod(...args) {
        const result = method.apply(this, args);

        console.log(
          `${propKey}(${args.join(",")}) = ${JSON.stringify(result)}`
        );

        return result;
      };
    }
  };
  return new Proxy(obj, handler);
}

const obj = {
  val: 2,
  double(x) {
    return this.val * x;
  }
};

const trackedObj = trackMethodCalls(obj);

trackedObj.double(4);

如果您要更改对象而不是通过代理对其进行检测,则应直接覆盖其方法:

function addTrackedMethods(obj) {
  for (const [methodName, method] of Object.entries(obj).filter(
    ([, method]) => typeof method === "function"
  )) {
    obj[methodName] = function interceptedMethod(...args) {
      const result = method.apply(this, args);

      console.log(
        `${methodName}(${args.join(",")}) = ${JSON.stringify(result)}`
      );

      return result;
    };
  }
}

const obj = {
  val: 2,
  double(x) {
    return this.val * x;
  }
};

addTrackedMethods(obj);

obj.double(4);

答案 1 :(得分:3)

如果没有在对象和调用它的事物之间进行修改或修改对象,就无法做到这一点。没有任何不涉及彼此的“互动”。

每一个:

彼此之间

如果您可以在对象和调用它的事物之间找到它们,则可以创建一个新的对象来执行此操作,其中的函数会复制调用它的目标对象上的函数。这是一个简单的示例:

const original = {
    value: 42,
    doSomething() {
        console.log(`original doSomething: this.value is ${this.value}`);
    },
    doSomethingElse() {
        console.log(`original doSomethingElse: this.value is ${this.value}`);
    }
};

const insertion = {};
for (const key of Object.keys(original)) {
    const func = original[key];
    if (typeof func === "function") {
        insertion[key] = function(...args) {
            console.log("insertion " + key + " [before]");
            const thisArg = this === insertion ? original : this;
            const result = Reflect.apply(func, thisArg, args);
            console.log("insertion " + key + " [after]");
            return result;
        };
    }
}

// Here's the code calling the object's methods;
// note we've gotten in the way by giving the code
// `insertion` rather than `original`:
insertion.doSomething();
insertion.doSomethingElse();

您也可以使用Proxy来做到这一点,尽管它更复杂并且在这种情况下,复杂性也无法为您带来任何好处。

请注意,出于明显的原因,这只会捕获通过insertion进行的呼叫。这意味着,如果doSomething调用doSomethingElse,在上面,您将拦截对doSomething的呼叫,而不是对doSomethingElse的呼叫。

修改对象

您可以通过替换对象的方法来做到这一点,就像这样:

const original = {
    value: 42,
    doSomething() {
        console.log(`original doSomething: this.value is ${this.value}`);
    },
    doSomethingElse() {
        console.log(`original doSomethingElse: this.value is ${this.value}`);
    }
};

for (const key of Object.keys(original)) {
    const func = original[key];
    if (typeof func === "function") {
        original[key] = function(...args) {
            console.log(key + " [before]");
            const result = Reflect.apply(func, this, args);
            console.log(key + " [after]");
            return result;
        };
    }
}

// Here's the code calling the object's methods
original.doSomething();
original.doSomethingElse();

由于这会修改对象本身,因此您会看到所有调用。