ES6 Proxy

This is the part of a series of blogs on the new features on the upcoming ECMAScript 6 (ES6) specification which JavaScript implements.

In this blog we focus on the Proxy object introduced in ES6.

We have briefly touched on the Proxy object in a previous blog on ES6’s Reflect API.

Proxy Object #

The Proxy object is used to define a layer of custom behavior in place of an object’s fundamental operations such as property lookup, assignment, enumeration, or function invocation.

The idea is we build traps on top of an object to intercept calls to fundamental operations to add our own layer on top of it.

Syntax:

var proxy = new Proxy(target, handler);

target

handler

Example: #

Consider the example below. quirrell is the container for the proxied object heWhoMustNotBeNamed while horcrux defines the traps where our custom layer is used rather than quirrell ‘s own fundamental operations.

let quirrell = {};
let horcrux = {
  get: function(target, name) {
    console.log(target);
    console.log(name);
    return name in target ? target[name] : "HE LIES!";
  }
};

var heWhoMustNotBeNamed = new Proxy(quirrell, horcrux);

heWhoMustNotBeNamed.wand = {
  core: "phoenix",
  wood: "yew",
  length: 13.5
};

heWhoMustNotBeNamed.wand;
// Object {wand: Object}
// "wand"
// Object {core: "phoenix", wood: "yew", length: 13.5}

heWhoMustNotBeNamed.wand.length === 13.5;
// Object {wand: Object}
// "wand"
// Object {core: "phoenix", wood: "yew", length: 13.5}
// "length"
// true

heWhoMustNotBeNamed.wand.isElderWand;
// Object {wand: Object}
// "wand"
// Object {core: "phoenix", wood: "yew", length: 13.5}
// "isElderWand"
// "HE LIES!"

Meanwhile, an empty handler object means the proxy is not forwarding its operations at all. So it acts as if no proxy method has been applied to it because all traps are optional. If a trap has not been defined, the default behavior is to forward the operation to the target.

The handler object can overrule many native fundamental operations, to see the full list go here.

Use Cases #

The Proxy object allows us to create defensive objects. #

Consider the scenario where you are debugging a program and it’s doing something stupid. Not until 8 hours later do you realize that instead of doing request.payload.data you are doing request.payload. Both are objects yet only one of them have the proper data inside of them that you need. With proxies we can defend against this by many means, from returning an invalid code to creating adapters inside of the object to even checking if the property is in the target before returning the result rather than returning undefined.

var stubProxy = new Proxy(stub, handler);

stubProxy.request.payload; // ERROR!
stub.request.payload; // Object {data: Object}

The Proxy object allows us to create defensive constructors. #

Consider the example below, in the ES5 way we would inevitabley not catch that the muggle has no powers. But in the Proxy way, we defend against such issues by truly checking our object before doing any fundamental operations.

function Wizard(name) {
    this.name = name;
    return createDefensiveObject(this);
}

let muggle = new Wizard("Dudley");

console.log(person.powers); // ERROR!

The Proxy object allows us to validate passed value for an object. #

Consider the example below, it effectively makes sure that the property isWizard is always boolean and never an truthy or a falsey.

let validator = {
  set: function(object, prop, value) {
    if (prop === 'isWizard') {
      if (typeof value !== 'boolean') {
        throw new TypeError('Value for isWizard is not a boolean');
      }
    }

    object[prop] = value;
  }
}

let harryPotter = new Proxy({}, validator);

harryPotter.isWizard = true;
console.log(harryPotter.isWizard); // true
harryPotter.isWizard = 1; // TypeError: Value for isWizard is not a boolean

The Proxy object allows us to create … better DOM implementations … yes! #

While most developers couldn’t care less about this, the Proxy object allows us to efficiently create DOM implementations by using only JavaScript. Most modern browsers are made up of a combination of C++ and JavaScript since handling DOM manipulations using only JavaScript would be terribly inefficient. However with the advent of the Proxy object, this can be resolved and would allow a wider range of developers to create DOM implmentations (think the separation of front end vs back end and BaaS solutions).

However, better DOM manipulations does mean better frameworks who virtualizes their DOM (think React).

P.S. #

Proxies can be revoke() meaning it shuts it down and does not allow the client to access an important resource (an object) directly, only via a reference (an intermediate object, a wrapper around the resource).

let { proxy, revoke } = Proxy.revocable(target, handler);
revoke();
console.log(proxy.isWizard); // TypeError: Revoked

Proxy handlers do have rules, you can’t just do whatever you want!

 
10
Kudos
 
10
Kudos

Now read this

ES6 Reflect API

This is the part of a series of blogs on the new features on the upcoming ECMAScript 6 (ES6) specification which JavaScript implements. In this blog we focus on the Reflect API introduced in ES6. Reflect Object # What is the Reflect API?... Continue →