我想知道在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);
}
也许有另一种方法可以实现此目的,而不是使用事件侦听器,但是我不知道。
谢谢!
答案 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();
由于这会修改对象本身,因此您会看到所有调用。