When the target is a function, apply(target, thisArg, args) runs on every call (including call(), apply() and callbacks) and construct(target, args, newTarget) runs on new and must return an object. Forwarding through Reflect.apply() and Reflect.construct() preserves this and new.target, so you can log, time, memoize or coerce arguments without touching the original code.
const sum = (...nums) => nums.reduce((a, b) => a + b, 0);
const logged = new Proxy(sum, {
apply(target, thisArg, args) {
console.log(`call ${target.name}(${args})`);
return Reflect.apply(target, thisArg, args);
},
});
class Point { constructor(x, y) { Object.assign(this, { x, y }); } }
const NumericPoint = new Proxy(Point, {
construct: (target, args, newTarget) => Reflect.construct(target, args.map(Number), newTarget),
});
console.log(logged(1, 2, 3), new NumericPoint("3", "4"));call sum(1,2,3)
6 Point { x: 3, y: 4 }