I want to create a constructor object whose inheritance works as normal, but capture the constructor so I can manipulate the instance object. Using Proxy()
almost solves this, but it seems to screw up the inheritance. Note the following example without a proxy:
> const B = function() {}
undefined
> B.name
'B'
> class C extends B {}
[Function: C]
> B.prototype == C.prototype.__proto__
true
> var instance = new C()
undefined
> C.prototype == instance.__proto__
true
> instance.__proto__
C {}
Now, if I add a proxy to capture construct(target,args)
, it will correctly capture the constructor, but it doesn't preserve things exactly as it would without the proxy. Note that all the constructor does is print a message to the console noting its capture. But otherwise (I think) it should react the same. However, when I create a class to extend the proxied function, it seems like the extended function is missing entirely. Note the last four lines give different results than above.
> const handler = { construct(target,args) {
... console.log('Captured!'); return new target(...args); } }
undefined
> const proxy_B = new Proxy(B, handler)
undefined
> proxy_B.name
'B'
> class C2 extends proxy_B {}
[Function: C2]
> proxy_B.prototype == C2.prototype.__proto__
true
> var instance2 = new C2()
Captured!
undefined
> C2.prototype == instance2.__proto__
false
> instance2.__proto__
B {}
What am I doing wrong? How do I write the proxy to properly handle this case?
In JavaScript, proxies (proxy object) are used to wrap an object and redefine various operations into the object such as reading, insertion, validation, etc. Proxy allows you to add custom behavior to an object or a function.
Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype. By definition, null has no prototype, and acts as the final link in this prototype chain.
The Proxy and Reflect objects allow you to intercept and define custom behavior for fundamental language operations (e.g. property lookup, assignment, enumeration, function invocation, etc.). With the help of these two objects you are able to program at the meta level of JavaScript.
A JavaScript Proxy is an object that wraps another object (target) and intercepts the fundamental operations of the target object. The fundamental operations can be the property lookup, assignment, enumeration, and function invocations, etc.
Your handler doesn't handle the new.target
. Notice that the target
of your proxy is B
, and when you return new target
then you'll construct a B
instance not a C
instance.
Instead of approximating the construction behaviour with new
, use the Reflect
object (in particular Reflect.construct
) to use the exact default construction behaviour and pass all the arguments of the trap method:
const handler = {
construct(target, args, newtarget) {
// ^^^^^^^^^
console.log('Captured!');
return Reflect.construct(target, args, newtarget);
// ^^^^^^^^^
}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With