Intercepting method calls via ES6 Proxies
This blog post explains how to use ES6 Proxies to intercept method calls to an object.
Read chapter “Meta programming with proxies” in “Exploring ES6” for more information on Proxies.
The problem
You can intercept the operation get
(getting property values) via a proxy and you can intercept the operation apply
(calling a function), but there is no single operation for method calls that you could intercept. That’s because method calls are viewed as two separate operations: First a get
to retrieve a function, then an apply
to call that function.
The solution
If you want to intercept method calls, you must therefore intercept get
and return a function that intercepts the function call. The following code (which works in Firefox) demonstrates how that is done.
function traceMethodCalls(obj) {
let handler = {
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;
};
}
};
return new Proxy(obj, handler);
}
I’m not using a Proxy for the latter task, I’m simply wrapping the original method with a function.
Let’s use the following object to try out traceMethodCalls()
:
let obj = {
multiply(x, y) {
return x * y;
},
squared(x) {
return this.multiply(x, x);
},
};
tracedObj
is a traced version of obj
. The first line after each method call is the output of console.log()
, the second line is the result of the method call.
> let tracedObj = traceMethodCalls(obj);
> tracedObj.multiply(2,7)
multiply[2,7] -> 14
14
> tracedObj.squared(9)
multiply[9,9] -> 81
squared[9] -> 81
81
The nice thing is that even the call this.multiply()
that is made inside obj.squared()
is traced. That’s because this
keeps referring to the proxy.
This is not a very efficient solution. One could, for example, cache methods. Furthermore, Proxies themselves have an impact on performance.
Comments
Post a Comment