Javascript: know which object function has been called - Stack Overflow

I would like to know if there is a way to be notified when any object function is called, in javascript

I would like to know if there is a way to be notified when any object function is called, in javascript.

For example, I would like to do something like the following:

If I have an object like this:

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

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

And add a listener (or anything else to track the actions taken place on this object):

myObject.addEventListener('onFunctionCall', functionHasBeenCalled);

When I call:

myObject.functionOne('hello');

The listener handler to fire with information about the called function:

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

And the console output to be:

functionOne has been called
with argument: hello

Maybe there is another way, to implement this, not with an event listener, but I have no clue.

Thanks!

I would like to know if there is a way to be notified when any object function is called, in javascript.

For example, I would like to do something like the following:

If I have an object like this:

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

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

And add a listener (or anything else to track the actions taken place on this object):

myObject.addEventListener('onFunctionCall', functionHasBeenCalled);

When I call:

myObject.functionOne('hello');

The listener handler to fire with information about the called function:

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

And the console output to be:

functionOne has been called
with argument: hello

Maybe there is another way, to implement this, not with an event listener, but I have no clue.

Thanks!

Share Improve this question edited Feb 26, 2019 at 14:40 ealef asked Feb 26, 2019 at 14:28 ealefealef 5543 silver badges12 bronze badges 4
  • 2 What do you mean with "object function"? A property of an object that is a function? Also when on the prototype? Look into Proxy – trincot Commented Feb 26, 2019 at 14:30
  • 1 What does functionName refer to? – kockburn Commented Feb 26, 2019 at 14:31
  • I have updated the question, so these questions are answered @kemicofa – ealef Commented Feb 26, 2019 at 14:42
  • I usually prefer using some variation of the mediator pattern to do these kind of things. – Shilly Commented Feb 26, 2019 at 14:50
Add a ment  | 

2 Answers 2

Reset to default 6

One approach could be to use a Proxy to create "tracked" objects where you intercept any method invocations:

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);

If you want to mutate an object rather than instrumenting it via a Proxy, you should just directly overwrite its methods:

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);

You can't do that without getting between the object and the thing calling it, or modifying the object. There isn't any "tap into this interaction" that doesn't involve one or the other.

Here's each:

Getting between them

If you can get between the object and the thing calling it, you can create a new object to do that, with functions duplicating the functions on the target object that call it. Here's a simple example:

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();

You can also do that with a Proxy, though it's more plicated and the plication doesn't buy you anything in this case.

Note that this will only catch calls make through insertion, for obvious reasons. That means if doSomething calls doSomethingElse, in the above you'd intercept the call to doSomething but not the call to doSomethingElse.

Modifying the object

You can do it by replacing the object's methods, like this:

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();

Since this modifies the object itself, you'd see all the calls.

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745636619a4637432.html

相关推荐

  • Javascript: know which object function has been called - Stack Overflow

    I would like to know if there is a way to be notified when any object function is called, in javascript

    2小时前
    10

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信