A Gentle Introduction To Proxy In JavaScript (Part-2)

A Gentle Introduction To Proxy In JavaScript (Part-2)

Reflect API

·

3 min read

Hi There,

I am on the stage for the second part of the Javascript Proxy article. If you did not read the first part, I highly recommend you read it first. Part1

I want to talk about Reflect API and its relation with Proxy today.

Reflect is a built-in object that simplifies the creation of Proxy.

It was said that internal methods, such as [[Get]], [[Set]] and others are specification-only, they can’t be called directly.

The Reflect object makes that somewhat possible. Its methods are minimal wrappers around the internal methods.

Here are examples of operations and Reflect calls that do the same

const user = {};
Reflect.set(user, 'name', 'John'); //is same as user.name = "John";
console.log(user.name); // John

When we normally set the user name as user.name = "Chety"; what is being done behind the scenes Javascript calls its internal [[Set]] method. As we said earlier in this article, these methods are internal and can not be called directly but somehow Reflect API make it possible. Reflect API has corresponding methods for Javascript internal methods(set for [[Set]], get for [[Get]]. Pretty intuitive right?). That means as you call Reflect.set(...), Reflect API will forward this call to the original object which is the internal [[Set]] method in this case.


We can use Reflect it with Proxy also. Below you can find a proxy creation for user. As always explanations will be provided with code :)

let user = {
     name: "Rodik"
}
user = new Proxy(user, {
    get(target,prop,receiver){
        console.log(`GET ${prop}`);
        //Reflect forwards operation to the original object
        return Reflect.get(target,prop,receiver); // or Reflect.get(...arguments)
    },
    set(target,prop,value,receiver){
        console.log(`SET ${prop} = ${value}`);
        //returning a truthy value means success. Otherwise 
        //update operation will not take place
        return Reflect.set(target,prop,value,receiver)
    }
})

user.name; //GET name
user.name = "Miran"; //SET name = Miran

For every internal method, trappable by Proxy, there’s a corresponding method in Reflect, with the same name and arguments as the Proxy trap.

Let us see some code examples, which can be tricky when not used Reflect with Proxy.

let role = {
    _name: "generic role",
    get name(){
        return this._name
    }
}

role = new Proxy(role,{
    get(target,prop,receiver){
        console.log(`GET METHOD CALLED.`);
        return target[prop]
    }
})
console.log(role.name); // GET METHOD CALLED. generic role

const admin = {
    __proto__: role,
    _name: "admin"
}

console.log(admin.name); //it prints generic role , but why ?

In the above code, we expect admin.name as admin but what we got is generic role. It is not what we expected. The reason lies in the Proxy mechanism. Since admin does not have a getter method or property called name, Javascript will look at its prototype which is role. Role object has a name-getter method thus Javascript calls this getter. That getter method invokes get trap which is defined by proxy. In our proxy get trap target is still role and role["name"] returns what? Wait for it... Of course generic role. So is the case resolved? Not quite yet. To solve this issue instead of returning, we should use Reflect.get(...) for forwarding get operation to the original object which in this case is admin. Our get trap should be like below.

      get(target,prop,receiver){
        console.log(`GET METHOD CALLED.`);
        //forward get operation to the original object  
        return Reflect.get(target,prop,receiver);
    }

That is all I have for you today. If you have any questions, comments, etc... just drop in the comments and I will reply as soon as possible. Until the next post, stay tuned, bye-bye.

Did you find this article valuable?

Support Chety by becoming a sponsor. Any amount is appreciated!