Proxy Pattern

Overview

The Proxy Pattern uses a Proxy intercept and control interactions to target objects.

Let's say that we have a person object. We can access properties with either dot or bracket notation,

and modify property values in a similar fashion.

With the Proxy pattern, we don't want to interact with this object directly. Instead, a Proxy object intercepts the request, and (optionally) forwards this to the target object - the person object in this case.


Implementation

In JavaScript, we can easily create a new proxy by using the built-in Proxy object.

Proxy

The Proxy object receives two arguments:

  1. The target object
  2. A handler object, which we can use to add functionality to the proxy. This object comes with some built-in functions that we can use, such as get and set.

The get method on the handler object gets invoked when we want to access a property, and the set method gets invoked when we want to modify a property.

const person = {
  name: "John Doe",
  age: 42,
  email: "[email protected]",
  country: "Canada"
}

const personProxy = new Proxy(person, {
  get: (target, prop) => {
    console.log(`The value of ${prop} is ${target[prop]}`)
    return target[prop]
  },
  set: (target, prop, value) => {
    console.log(`Changed ${prop} from ${target[prop]} to ${value}`);
    target[prop] = value;
    return true;
  }
});

Reflect

The built-in Reflect object makes it easier to manipulate the target object.

Instead of accessing properties through obj[prop] or setting properties through obj[prop] = value, we can access or modify properties on the target object through Reflect.get() and Reflect.set(). The methods receive the same arguments as the methods on the handler object.

const personProxy = new Proxy(person, {
  get: (target, property) => {
    return Reflect.get(target, property);
  },
  set: (target, property, value) => {
    return Reflect.set(target, property, value);
  }
});

Tradeoffs

Control: Proxies make it easy to add functionality when interacting with a certain object, such as validation, logging, formatting, notifications, debugging.

⚠️ Long handler execution: Executing handlers on every object interaction could lead to performance issues.


References