DEV Community

yanai
yanai

Posted on

The Power of Proxy Api

https://pixabay.com/

Recently I helped in translating the book “Understanding ECMAScript 6" to Hebrew (for now the translation process still at work).

That triggered an interest in the wonderful world of javascript’s Proxy Api- and in this short article I want to present some of the power of this API and show you some useful parts.

So, what is Proxy After all? And why do we need it?

Good questions let’s try to answer them.

Some History

Before ES6, The ES5 gave us the ability to decide if a property of a given object is configurable , enumerable , writable and so on see here.

The ES6 is giving the developer more power to control the object’s behavior and give accesses to JS engine capabilities- through Proxies low-level operations of the JavaScript engine.

For example :using proxy you can extend the object to mimic and act like an array- you can read about it in the section “The Array Problem".

Let see a basic use of proxy:

let targetObject= {}let proxy = new Proxy(targetObject , {})  
proxy.name = 'my name';console.log(proxy.name) // "my name"  
console.log(targetObject.name) // "my name"

When you create a Proxy object you need to pass two parameters to the proxy constructor. the target Object and a handler.

The handler is an object that defines one or more “traps”. A trap is some endpoint to interact with the low-level-api. For example one could trap an object’s getter method and overide it .

let targetObject = {  
    massage: "hello world",  
    name: "foo"  
};  

let proxy = new Proxy(targetObject, {  
 /// 'get' trap  
    get(trapTarget, key, value, receiver) {  
        if (key === 'massage'){  
           return "hello proxy";  
        }  
       return Reflect.get(trapTarget, key, value, receiver);  
    }  
});

console.log(targetObject.massage) /// 'hello world'  
console.log(proxy.massage) /// 'hello proxy'
console.log(targetObject.name) /// 'foo'  
console.log(proxy.name) /// 'foo'

This article will present some of the most interesting traps that proxy offers us.

Reflection API

Before moving to the amazing traps… we need to be familiar with reflection API. Because Proxy has an access to the low level methods in JS.

The reflection API- is a collection of methods that serve the default behavior of the same low level methods- for every trap- we have a reflect method …

This is a quick summary:

The following is a list of methods provided by the reflection API.

In order to call the default low level object’s mathods one needs to use the reflect API. (as we will see next)

https://github.com/nzakas/understandinges6/blob/master/manuscript/12-Proxies-and-Reflection.md

So now we have more basic knowledge to continue- and show you the next cool trap in proxy.

Preventing Property Deletion

In an object we have the method deleteProperty so similarly proxy has the deleteProperty trap- it is useful for a lot of things- the basic one is to prevent deletion of property:

let  targetObject  =  {  
   name: "target",  
   lock: "delete not allowed"  
};

let proxy = new Proxy(targetObject,  {  
    deleteProperty(trapTarget, key){  
       if(key === 'lock'){  
          throw new Error('this props are lock')  
       }else{  
        return Reflect.deleteProperty(trapTarget, key)        
      }  
     }  
});

The reflect method - it for execute the default behavior…let see it in action:

Alt Text

Blocking defineProperty

The definePropery method get three values as arguments: Object.defineProperty(obj,prop,descriptor) as you can see here , let see the trap example:

let targetObject = {  
   name: "target",  
};  
let proxy = new Proxy(targetObject, {  
    defineProperty(trapTarget, key, descriptor){  
       if(key === 'lock'){  
          throw new Error('this props cannot be defined')  
       }  
        return Reflect.defineProperty(trapTarget, key, descriptor)        
     }  
});

And in action :

Using this trap you can also to make sure that the object structure is what we expect.

Hide Property with has trap

You can check if Property exists on object with the in operator, like that:

const targetObject = {foo: 'bar'}  
console.log("foo" in targetObject ) // true

With the has trap you can hide this Property:

Function proxy- apply and construct

Of all the proxy traps- the apply and construct traps, requires the target to be a function.

With the apply and construct tarps you can do anything before the apply call or the new proxy() is execute.

It so Powerful !!!
Alt Text

Cancel the Proxy

By default when you create proxy, the proxy is bounded to its target since creation and for its entire existence.

Sometime it can be useful to cancel this binding, like in cases of , for example if you expose Object api (by proxy of course) and the token is no longer valid- you can terminate the object api by canceling the proxy.

A revocable proxy can be create like that:

let  targetObject  =  {  
   name:  "target"  
};
let {proxy, revoke}= Proxy.revocable(targetObject,  {});

console.log(proxy.name);        // "target"  
revoke();
console.log(proxy.name); // throw an error

The Proxy.revocable- receives two parameters as any proxy- but return us the revoke function that give us the ability to cancel the binding to the target-

as we can see in the example.

Let see a simple example with react

As you can see- with proxy you take the object to the next level: you can interact with the low level, validate before delete key in object , take object and append to it all array’s methods (this is needed to implement array’s rules) -check it here , and more.

For more information, refere to Understanding es6 book and the MDN.

Alt Text

Hope you found this short article useful. Now go and take your objects to the next level !!!🚀🚀🚀

Browser support… all the browser is supported (Except from old IE 😒)

Thanks For Reading.

Yanai.

Top comments (0)