Using Proxy() in Javascript to Detect Changes

01 Aug 2019

I ran into an issue with my side project AoS Reminders recently where I was mutating an object that wasn’t supposed to be mutated.

I was having trouble tracking down the mutation, until I stumbled upon the Proxy object, a helpful tool for any Javascript developer.

const obj = { key1: 'value', key2: 'value2' }

const handler = {
  get(target, key) {
    console.log('Reading value from ' + key)
    return target[key]
  },
}

const proxiedObj = new Proxy(obj, handler)

// When we run this `if` statement, console will log
// 'Reading value from key1'
if (proxiedObj.key1) { }

This can be useful for detecting when your objects are being accessed.

Another great example of using Proxy is for object validation:

// Use the proxy handler as a validator
const validator = {
  set: (obj, prop, value) => {
    // Validate that we passed in a correct `type` value
    if (prop === 'type') {
      const validTypes = ['Mage', 'Barbarian', 'Archer']
      if (value === null) {
        throw new TypeError('Cannot set to type to null');
      }
      if (!validTypes.includes(value)) {
        throw new TypeError('Cannot set to type to ' + value);
      }
    }

    // Store the new value in your object
    obj[prop] = value;

    // `set` expects a boolean response if successful
    return true;
  }
};

let char = new Proxy({age: 40, stars: 5}, validator);

char.name = 'Dennis'      // Other keys are not validated
char.type = 'Golden God'  // Throws `Cannot set to type to Golden God`
console.log(char.type)    // undefined
char.type = 'Mage'        // Passes validation
console.log(char.type)    // 'Mage'
char.type = null;         // Throws `Cannot set to type to null`
console.log(char.type)    // 'Mage'

While useful, you should really be using Typescript and enforcing your object keys that way ;)

Hope this helps someone! Just thought I’d share a small, neat feature of JS I hadn’t used before.