DEV Community

Rafi
Rafi

Posted on

Using javascript proxy

I have recently been digging into proxy in Javascript. I was surprised by what it can do. Proxy allows you to hook into fundamental operations of the language constructs (like object, arrays, functions..)

Here is list of simple usecases for javascript proxy

Freezing Object

We can prevent mutation of objects easily with few lines of code essentially freezing the object

 const hero = {
   name: 'Saitama',
   age: 25,
   class: 'B',
   race: 'Human',
   heroName: 'Caped Baldy',
 };

 const Freeze = obj =>
   new Proxy(obj, {
     set: function(target, key, value) {
       throw Error("You can't change values this object has been frozen");
     },
   });

 const saitama = Freeze(hero);
 saitama.name = 'Garuro';   // This will throw error
Enter fullscreen mode Exit fullscreen mode

You can also freeze arrays, Map, WeakMap, Set...

Tracking changes on object

Proxy can be used track changes to object essentially maintain history.

 const createHistory = obj => {
   let history = [JSON.parse(JSON.stringify(obj))];
   const proxiedObject = new Proxy(obj, {
     set: function(target, key, value) {
       history.push({ ...target, [key]: value });
       Reflect.set(target, key, value);
     },
   });
   return [history, proxiedObject];
 };

 const [history, proxiedObject] = createHistory(hero);
 proxiedObject.name = 'Genos';
 proxiedObject.class = 'C';

 console.log(history);
Enter fullscreen mode Exit fullscreen mode

history object will contains snapshot of changes made to the object

 [
   {
     name: 'Saitama',
     age: 25,
     class: 'B',
     race: 'Human',
     heroName: 'Caped Baldy'
   },
   {
     name: 'Genos',
     age: 25,
     class: 'B',
     race: 'Human',
     heroName: 'Caped Baldy'
   },
   {
     name: 'Genos',
     age: 25,
     class: 'C',
     race: 'Human',
     heroName: 'Caped Baldy'
   }
 ]
Enter fullscreen mode Exit fullscreen mode

similarly you can also track number of times function was called with apply trigger.

Case insensitive key access

 const caseInsensitive = obj =>
   new Proxy(obj, {
     get: function(target, key) {
       // I am assuming keys are lowercase by default for simplicity
       return Reflect.get(target, key.toLowerCase());
     },
   });

 const proxiedObject = caseInsensitive(hero);
 console.log(proxiedObject.name); // saitama
 console.log(proxiedObject.NAME); // saitama
Enter fullscreen mode Exit fullscreen mode

Handling properties that does not exist

You can easily handle undefined properties by following snippet

 const FetchValue = obj =>
   new Proxy(obj, {
     get: function(target, key) {
       if (target.hasOwnProperty(key)) {
         return [Reflect.get(target, key), true];
       }
       return [null, false];
     },
   });


 const proxiedObject = FetchValue(hero);

 const [name, nameExist] = proxiedObject.name;
 const [city, cityExist] = proxiedObject.city;

 if (nameExist) {
   console.log(name);
 }

 if (cityExist) {
   console.log(city); // this is not executed since property city does not exist
 }
Enter fullscreen mode Exit fullscreen mode

You can do much more with proxy than what is listed here. You can look up more awesome usage here https://github.com/mikaelbr/awesome-es2015-proxy

Top comments (0)