Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proxy ES6 class and maintain prototype chain

I'm proxying methods using the following wrapper:

  public static wrap(target) {
    function construct(constructor, args) {
      const c: any = function(this) {
        return constructor.apply(this, args);
      };

      c.prototype = constructor.prototype;
      return new c();
    }

    const f = (...args) => {
      const instance = construct(target, args);

      const descriptors = getMethodDescriptors(target, instance);

      return new Proxy<T>(
        instance,
        new SomeProxyHandler(descriptors)
      );
    };

    f.prototype = target.prototype;
    return f;
  }

This has worked well when wrapping classes which are compiled down to ES5 but now I'm trying to target ES6 I'm getting errors at constructor.apply(this, args) saying that:

TypeError: Class constructor OneOfMyClasses cannot be invoked without 'new'

How can I fix this code so wrap can proxy classes whatever the JavaScript target and maintain the correct prototype chain?

like image 973
Tim Avatar asked Feb 22 '19 20:02

Tim


People also ask

What is ES6 proxy?

ES6 implements intercession form of meta programming using Proxies. Similar to ReflectAPI, the Proxy API is another way of implementing meta programming in ES6. The Proxy object is used to define custom behavior for fundamental operations. A proxy object performs some operations on behalf of the real object.

What is the difference between proxy constructor and reflect?

So Proxy is a wrapper which can be used to intercept fundamental operations like [[Get]] and [[Set]] on an object whereas Reflect provides us minimal wrappers around these fundamental operations like [[Get]] and [[Set]] so that we can call them directly (Usually from inside the trap).

What is prototype chain in JavaScript?

Every object in JavaScript has a built-in property, which is called its prototype. The prototype is itself an object, so the prototype will have its own prototype, making what's called a prototype chain. The chain ends when we reach a prototype that has null for its own prototype.

How is inheritance implemented in ES6?

This can be done using the extends and super keywords. We use the extends keyword to implement the inheritance in ES6. The class to be extended is called a base class or parent class. The class that extends the base class or parent class is called the derived class or child class.


1 Answers

The easiest way would be spread syntax

const instance = new target(...args);

but you can also use Reflect.construct:

const instance = Reflect.construct(target, args);

This will even be necessary if your wrapped classes are supposed to be extensible, you then will have to make use of new.target:

const instance = Reflect.construct(target, args, new.target);

Btw, your f wrapper should be a proper function not an arrow function, as those cannot be called with new (and don't have new.target). Or maybe even simpler (working better with static methods and inheritance), just wrap the whole target class itself in a Proxy and use its construct trap.

like image 167
Bergi Avatar answered Nov 13 '22 21:11

Bergi