Checkout my CSS Grid By Example and Getting Started With React video courses on Skillshare. Sign up now and get one free month of Skillshare.

Working with Javascript proxies, private fields and the Reflect API

Let's say we have the following class declaration:

class Dog  {
  #name

  set name(n) {
    if(n ==="abc" ) {
      throw new Error("Provide a longer name")
    }
    this.#name = n
  }

  get name() {
    return this.#name
  }
}

The name property is marked as a private filed.

We want to add a Javascript proxy so that we can intercept and modify the behavior of the set name() method. We want to add an extra validation condition:

let handler = { 
    set: (obj, property, value) => { 
        if (property.length < 2) { 
            throw new Error("The name should be longer than 2 characters.")
        } 
        return obj[property] = value
    }
};

let d = new Dog()
const proxyedDog = new Proxy(d, handler)
proxyedDog.name = "abc"

However, there are 2 problems with this approach:

  1. having the obj[property] = value will mess up the initial intention of the setter when we do proxyedDog.name = "abc"
  2. if we try to access the name attribute, by loging proxyedDog.name we will get the bellow error:
console.log(proxyedDog.name)
//Uncaught TypeError: Cannot read private member #name from an object whose class did not declare it 

Using the Reflect API to invoke the original getters and setters from a Javascript proxy

Both of the above problems will be solved if we find a way to access the original getters and setter methods from within the proxy.

Here comes into play the Javascript Reflect API.

All of the methods of the Reflect class are static so they will be invoked with syntax like Reflect.doStuff().

It works by giving it an object and asking it to call something from it. So, for example, if we want to call a setter we will have:

Reflect.set(obj, property, paramter)

Steve Griffith has a great video explaining more about the Reflect API:

With this in mind, we can now update our proxy as this:

let handler = { 
    set: (obj, property, value) => { 
        if (property === 'name') { 
            throw new Error("Provide a longer name")
        } 
        return Reflect.set(obj, property, value)
    },
    get: (obj, property, value) => { return Reflect.get(obj, property)}
};

This will fix both the setter and getter by calling their initial form.

Using the Reflect API to invoke any method from a Javascript proxy

As a final note when using the Reflect API we are not limited just to setters and getters. We can call any method by using the apply method:

Reflect.apply(target, thisArgument, argumentsList)
Home Screencasts Best of Newsletter Search X