Understanding Javascript Proxy Object

Understanding Javascript Proxy Object

Understanding and How to Use Javascript Proxy Object

What Are Javascript Proxy Objects?

Proxy objects are straightforward wrappers for another object and are capable of intercepting and redefining the fundamental operations for that object.

Explaining Proxy Object In A Layman Language.

Imagine you have a toy and only want your friends and anyone with a code to access it.

You can go ahead and put the toy in a box, and only people with the password used to lock the box can access it.

The lock you have put in place is an excellent example of what a proxy can do.

So a javascript proxy object is like a helper that is capable of watching over another object and controlling what you can do with them.

The object can be any type of javascript object, e.g. {}, [], functions, and it can be another proxy. So another proxy can be proxied. Below is a syntax for defining a javascript proxy.

const target =  {};
const handler = {};

const proxy = new Proxy(target, handler);

Common Terms

Object Internal Methods: Objects naturally houses a collection of properties. The internal methods are called to access or perform any form of operation on these properties; for every internal method, there is a corresponding trap method. When you try to access a property in a javascript object, the [Get] internal method is called. These methods cannot be called directly by name; it is used behind the scene by the language.

Target: It is the object you intend to wrap and control its usage, and it can be any javascript object, including functions.

Handler: It is simply an object with “traps” methods that guide/control or intercepts the operations you perform on objects wrapped in a proxy. Examples of traps are get and set.

Traps: Traps are simply functions that can be used to define the behaviour of an object's internal method. There is a 1 to 1 relationship between object internal methods and traps, i.e. for every internal method, there is a corresponding trap method.

Invariant: This explains rules that must be followed when using traps to intercept calls made to internal object methods. These conditions must be fulfilled by both the internal method and trap consecutively. Set and delete traps must return true or false depending of the operation performed is successful.
To see a complete list of invariants, you should visit the Full List of Invariants.

Objects Internal Methods and Corresponding Trap Function

Objects internal methods and Trap function from developer mozilla

Credit to: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Getting Our Hands Dirty With Some Examples Of How You Can Make Use Of Proxy

Enough of the theory; I hope you have made it to this stage and itching to see how to implement and use proxy objects.

Example 1: Providing a default value when accessing a property that does not exist on an object

const arrayOfNumber = [9, 8, 7, 3];

const firstHandler = {
  get(target, property) {
    if (property in target) {
      return target[property];
    } else {
      return 0; // default value
    }
  }
}
const arrayOfNumberProxy = new Proxy(arrayOfNumber, firstHandler);

//Accessing an in index that does not exists on an the array object that is not "proxied"
console.log(arrayOfNumber[9]); // Result: undefined

// Accessing an index that does not exists
console.log(arrayOfNumberProxy[9]); // Result: 0

//Accessing an index that exists prints the result like normal array will behave
console.log(arrayOfNumberProxy[1]); // Result:  8

In the example above, we are basically providing a default value in a situation whereby you try to access an index that does not exist; you get zero; this way, we changed the default behaviour of accessing a value from a javascript object.

Example 2: Monitory access of object properties using the "get" trap method.

const calculator = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b,
};

const handler = {
  get(target, property) {
    const value = target[property];
    if (typeof value === "function") {
      return (...args) => {
        console.log(value, target);
        console.log(`Calling ${property} with arguments:`, args);
        const result = value.apply(target, args);
        console.log(`Result:`, result);
        return result;
      };
    }
    console.log(`Accessed property: ${property}`);
    return value;
  },
};

const loggingProxy = new Proxy(calculator, handler);

loggingProxy.add(10, 3); 
// Output: Calling add with arguments: [10, 3]
// Result: 13

loggingProxy.subtract(10, 3); 
// Output: Calling subtract with arguments: [8, 4]
// Result: 7

loggingProxy.name;

//Accessed property: name

In the example above, you notice we passed the target, which is the calculator object that contains two functions, add and subtract and a handler that contains the "get" trap method.

Example 3: Make sure the correct type is provided when setting the value of an object "set" trap method.

const user = {};

const handler = {
  set(target, property, value) {
    if (property == "age" && typeof value !== "number") {
      throw new Error(`${[property]} must be a number`);
    }
    if (property == "name" && typeof value !== "string") {
      throw new Error(`${[property]} must be a string`);
    }
    target[property] = value;
    return true;
  },
};

const userTypeCheckProxy = new Proxy(user, handler);

userTypeCheckProxy.age = 25;
console.log(userTypeCheckProxy.age); // Output: 25

userTypeCheckProxy.age = "thirty"; // Throws an Error: age must be a number

userTypeCheckProxy.name = "John Doe";
console.log(userTypeCheckProxy.name); // Output: John Doe

userTypeCheckProxy.name = 90292; // Throws an Error: name must be a string

In the above example, we create a target as our user object. By checking the property name we are trying to set, we can intercept the operation by using the trap set method and validate that the correct type is passed. If the correct type is passed, we simply allow the value to get set; otherwise, we throw an error.

Closing

I hope with the examples and explanation I have provided. You understand what proxy objects can do and how some of these trap methods can be used In your daily development.

This topic will be treated on my further on my Youtube Channel. We will provide more examples and implement more trap methods(), as the video has not yet been aired at the time of writing this article. Please kindly subscribe to my Youtube Channel and provide feedback.

I will appreciate your feedback and comments on how I can improve and suggestions on topics you would like me to talk about.