
Proxy, a new JavaScript ES6 feature - tirthbodawala
https://www.atyantik.com/proxy-javascript-es6-feature/
======
philbo
A use case I had for proxies was a circular array type:

[https://github.com/philbooth/hoopy](https://github.com/philbooth/hoopy)

If the index overflows in either direction, loop back round to the start/end
of the array. I wanted a circular array to use as a fixed-length buffer for
receiving data in a streaming JSON parser I wrote:

[https://github.com/philbooth/bfj/blob/61087c194d5675c75569a2...](https://github.com/philbooth/bfj/blob/61087c194d5675c75569a2e08617a98609b16ead/src/match.js#L197-L201)

~~~
lioeters
A circular array type, love it! It looks like an excellent use case of
proxies.

~~~
flashgordon
Technically the type should still be an Array with the backing implementation
having a circular array behavior no?

~~~
lioeters
Indeed, it extends native Array:
[https://github.com/philbooth/hoopy/blob/master/index.js#L3](https://github.com/philbooth/hoopy/blob/master/index.js#L3)

------
matsemann
I used proxies to make a fun library where you can call arbitrary functions,
and it tries to make the function based on the name. For instance

    
    
      declaraoids.findWhereNameEqualsX(persons, {x: "Mats"});
    

It will generate the function on the fly.

[https://github.com/Matsemann/Declaraoids](https://github.com/Matsemann/Declaraoids)

~~~
Vinnl
Haha that's a hilarious abomination :)

It's a shame it doesn't have declaraoids.makeMeASandwich() on the roadmap
though.

~~~
throwaway2016a
You should submit a pull request.

In fairness, some RPC web frameworks do this in a completely non-ironic non-
joke way. CakePHP "findBy" comes to mind.[1]

[1] [https://book.cakephp.org/2.0/en/models/retrieving-your-
data....](https://book.cakephp.org/2.0/en/models/retrieving-your-
data.html#findby)

~~~
twic
Also Java's Spring Data:

[https://docs.spring.io/spring-
data/commons/docs/current/refe...](https://docs.spring.io/spring-
data/commons/docs/current/reference/html/#repositories.query-methods.query-
creation)

Wasn't it an ActiveRecord thing to begin with? Spring got a lot of its more
recent awful features by trying to copy Rails.

~~~
jon-wood
And somewhat ironically Rails deprecated the particularly magical features
like `find_by_name("Bob")` aliases in favour of saner variants like
`find_by(name: "Bob")`.

~~~
always_good
What a great change.

It always seemed ridiculous to put the lookup key and lookup value in two
different places.

Nice to see Rails reconsider these things I once thought it would never
surrender.

~~~
bobbyi_settv
Ruby didn't have keyword arguments when they came up with the initial
approach.

~~~
always_good
That's not why they did it.

For example, they could've used maps:

    
    
        find_by name: "foo"

------
sametmax
As a Python guy, where we have __setattr__, __setitem__, etc., I was at first
wondering why you would use a proxy for such a thing. Better make it part of
the language.

But the more I think about it, the more I can see that it's handy to have an
official proxy interface for this, for the case of an external code needing to
wrap your object.

Also, I've seen so many reinvented wheels for proxies, and usually bad ones,
as it seems an easy problem to solve, but there are plenty of edge cases.
Proxies avoid the recursive problem altogether.

Besides, __dundermethods__ tend to make the language hard to optimize.

Still, it's really overkill for simple cases like the ones addressed by
Object.defineProperty (or @property for Python), as you create a huge layer of
indirection for the entire wrapped object. So if you use such a Proxy, you
better have a damn good reason.

~~~
mateuszf
I think it's a matter of performance. Compiler / interpreter / runtime will
only add overhead in lookups for this objects explicitly matched as proxy, but
in normal case it can go directly to the cached functions.

------
SimeVidas
I’d rather read an article that _doesn’t_ focus on the API (which I can look
up on MDN), but rather on the practical use cases (which are merely a footnote
in this article ).

~~~
mxschumacher
I agree: get to production uses with code examples as quickly as possible.

Tough to know whether this is a fringe feature or actually useful on a regular
basis without really digging in. Luckily, other comments here highlight some
usecases.

------
kevincennis
Proxies can also be really helpful for unit tests.

Obviously you have things like sinon for stubbing out methods, but they do
have to modify the original object, which I don’t think anybody _loves_.

But you can also wrap your object in a Proxy with handlers that stub certain
methods.

You can also use proxies to implement validation and observability on objects.
Here’s a very minimal example of a sort of Backbone-esque Model class with
proxies:
[https://gist.github.com/kevincennis/25ba31b2e9f9c8b7a34047ba...](https://gist.github.com/kevincennis/25ba31b2e9f9c8b7a34047ba0108aff0)

------
sfa_aok
Salesforce use this in their Lightning Framework. I've not gone beyond the
surface of that framework, but I've found its use of proxies adds friction to
development. Trying to debug in the browser, anything other than a primitive
results in a looking at an empty Proxy object - I believe this is a deliberate
choice behind the framework in the name of security. But it makes it much
harder to discover what's in an object - if you don't know the name of a
property, good luck getting it.

Note that this is either due to how the framework uses Proxy, rather than
Proxy itself, or I'm doing it wrong and should do more reading up on it. It
really could be the latter - given my level of experience and knowledge, I
thought hard about posting this comment!

~~~
hajile
Everything about the Salesforce JS experience from the ground up is horrible.
They'd have to pay me a lot more money to do that again.

------
fergie
This is new to me, and it took me a while to see the point, but having read
the Mozilla docs ([https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)) I can see a few use
cool examples of validation and input correction. That said- all of these
things _seem_ to be fairly trivial to achieve without proxies, so I am
wondering- what is the killer use-case that you absolutely positively need js
proxies for?

~~~
yashthakur
You can use them to call some functions when an object property is called or
set. P.S. Just like Database triggers ;).

You can use them conditionally to manipulate data before fetch or before
storing. For example: you want to store the username when a person registers
using the email id like userzyx@gmail.com then you can use it to generate
username from it by truncating the later part and generate unique username
which will be "userzyx" here.

Just open up your brains and see where further it can be used and
possibilities are just unlimited.

~~~
fergie
You are essentially restating my question: what _are_ the possibilities with
proxies? (What can you do with proxies that is much more
messy/difficult/verbose to do otherwise?)

~~~
foob
One possibility is adding syntactic sugar to objects. I posted elsewhere in
this thread about how we used them in Remote Browser, but here's a simple
example of adding support for negative indexing to an array. This basically
creates a shorthand for _array[-n] === array[array.length - n]_.

    
    
        class MyArray extends Array {
          constructor(...args) {
            super(...args);
            return new Proxy(this, {
              get: (target, name) => {
                if (name && name.match && name.match(/^-\d+$/)) {
                  return Reflect.get(target, this.length + parseInt(name, 10));
                }
                return Reflect.get(target, name);
              },
              set: (target, name, value) => {
                if (name && name.match && name.match(/^-\d+$/)) {
                  return Reflect.set(target, this.length + parseInt(name, 10), value);
                }
                return Reflect.set(target, name, value);
              },
            });
          }
        }
    

You could accomplish the same thing by creating explicit setters and getters,
but proxies allow you to directly intercept and modify the behavior of
property access, calling an object like a function, _etc_. This sort of
flexibility allows you to create APIs that wouldn't be possible otherwise.

------
cwp
I use this for sql queries:

    
    
      const user = await db.connect(sql => sql.getUserById(43))
    

The _sql_ value is a proxy that looks for a file called 'getUserById.sql',
reads sql out of it, sends the query to the database, and returns a promise
for the result. With caching and some sugar methods, it's a pleasant way to
use a database.

------
sgdesign
I was talking about this with a friend and he remarked that this could lead to
some pretty opaque code where things behave differently from what you'd
usually expect. While I think this is a cool feature, I think I agree with him
that you probably want to think twice before using Proxies.

------
nathanstitt
I used object proxy to create a DSL for constructing object factories,
inspired by Ruby's FactoryBot [https://github.com/nathanstitt/object-factory-
bot](https://github.com/nathanstitt/object-factory-bot)

It's pretty handy for generating data for unit tests, but wouldn't recommend
it for production code since I've discovered Proxy is fairly slow.

------
loftyal
Anyone using redux, I created this using proxies -
[https://github.com/alnorris/redux-
actiontyper](https://github.com/alnorris/redux-actiontyper)

------
hackerbabz
Why is this an ES6 feature? Isn't ES6 set and implemented? Wouldn't this be
part of a future spec (ES2018, ES2019, or whatever)?

~~~
taco_emoji
[https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#Browser_compatibility)

It's not "new" at all, Firefox has had it since v18 (mid 2012 [0]), Chrome
since v49 (early 2016 [1]), etc.

[0]
[https://en.wikipedia.org/wiki/Firefox_version_history](https://en.wikipedia.org/wiki/Firefox_version_history)

[1]
[https://en.wikipedia.org/wiki/Google_Chrome_version_history](https://en.wikipedia.org/wiki/Google_Chrome_version_history)

------
syspec
The use of `document.write` for this entry instead of the usual console threw
me off at first.

~~~
tlrobinson
Presumably so you can see the output in the embedded JSFiddles.

FYI, if you're embedding a JSFiddle you could also just drop this in the HTML
section then use console.log:

    
    
        <script>console.log = function(str) { document.write(str, "<br/>") }</script>

~~~
sametmax
JSFiddle should just have a tick box with "intercept console.log" and a tab
with the output .

~~~
tirthbodawala
Hahahaha...It should!

------
techsin101
This is another feature that goes into bucket "I'll never use" along
generators

~~~
sametmax
Generators require a mind switch to be used regularly. And the browser is not
the place where the most obvious use cases are, so it's harder to make your
first steps here.

The easiest things to start using generators is to write sysadmin scripts that
parse big files. Once you've done that, you get the memory benefit. Then the
more you use it, the more you get the lazy evaluation benefit and you start
using it elsewhere.

It's clearer in Python because:

\- generators have there for ever

\- we have unified way of iterating on things, and generators just work
transparently

\- you can start learning generators by just changing [] to () in your
comprehension lists

So in JS it's much less obvious.

~~~
icc97
Yeah, lazy evaluation is the big feature of generators. Given that it's such a
powerful feature of Haskell it's definitely worth investigating them.

------
Too
I can see a very valuable use case for being able to intercept method calls
and attribute lookups to do input validation, logging, etc. But being able to
dynamically decide which attributes exists sounds like a nightmare from a
code-analysis perspective.

Python has had the __getattr__, __setattr__ and friends and once you start
using them to be "creative" all static type checkers break down. They are
usually frowned upon.

Let's hope typescript is able to interpret these Proxy objects and that the
community don't abuse them for all kinds of strange things.

------
liberatus
Big win for JavaScript DSL composers. Reminds me of method_missing and other
sharp knives in ruby.

------
13years
I implemented JavaScript Safe Navigation using proxies as an experiment to
learn more about proxies.

This is similar to the TC39 Optional Chaining Proposal
[https://github.com/TC39/proposal-optional-
chaining](https://github.com/TC39/proposal-optional-chaining)

[https://gist.github.com/dakaraphi/6a87168db66fd8f032d2](https://gist.github.com/dakaraphi/6a87168db66fd8f032d2)

------
haikuginger
This makes sense to me - it feels like an interface somewhere in the space of
Python's properties (using the @property decorator), its descriptor
protocol[0] with which properties are implemented, and its system of magic
methods like __getattr__ and __getattribute__.

I am a bit intrigued about the way it's separated from the "nature" of the
underlying Object though - in Python, we'd have a single canonical interface
to the data, bound to the class in which the data was instantiated. Here, in
ES6, it seems like the data might be attached to a base Object, and you could
use that Object with any number of different proxies to provide polymorphic
behavior.

Overall, these seem like very different philosophies of object-oriented
programming. Which I guess makes sense given how the languages have evolved
over time.

[0]
[https://docs.python.org/3/howto/descriptor.html](https://docs.python.org/3/howto/descriptor.html)

------
isuckatcoding
[https://caniuse.com/#feat=proxy](https://caniuse.com/#feat=proxy)

Seems to have a decent coverage for most users

~~~
throwaway2016a
The issue is that for many applications anything less than ~98% is not
acceptable (eCommerce for instance). This is 87% (to save people a click).

And because this works on fundamental operators, a polypill is impossible.

However, if you are using Babel to transpile your JS or using Node.js this
seems like it could be very useful.

~~~
franciscop
You also cannot transpile Proxies, since they do not have an equivalent in
"old javascript" as they are a feature in such a level that cannot be built
with previous tech.

~~~
throwaway2016a
You can transpile pretty much anything. The transpiler doesn't have to just
modify the declaration, it can also modify the calls...

[https://www.npmjs.com/package/babel-plugin-
proxy](https://www.npmjs.com/package/babel-plugin-proxy)

> they do not have an equivalent in "old javascript"

Sure they do. Function calls.

~~~
franciscop
Ah totally, I misspoke. I was talking from the point of view of a library
author, where I'd like to transpile my code so anyone can include the library
and use it. In the same way I can use _const_ , transpile my code and no one
worries about me using _const_ internally, the same cannot be said for Proxy.

So, between everyone having to transpile their client code or losing the few
devs who need to support IE, I prefer the latter for my projects.

------
jaequery
I'm not really a fan of these "magic" code creators. I'd use it only as
required and not all out.

------
colept
Proxy is nice but the scope is very limited if you tend to avoid
metaprogramming.

One use I've found is for library maintainers - a way to expose a large API
without taking a hit for requiring the whole thing. We use it to consume parts
of that API without having to require all the dependencies and
subdependencies.

------
_bxg1
Proxies are awesome. I used them to create observables that automatically
publish on any mutation, no matter where in the object tree it happens:
[https://www.npmjs.com/package/mutable-
model](https://www.npmjs.com/package/mutable-model)

~~~
alessioalex
Cool stuff, I made a more general use library that notifies you of any chance
on an object property, no matter how nested it is:
[https://github.com/alessioalex/recursive-object-
proxy](https://github.com/alessioalex/recursive-object-proxy)

------
caxco93
This isn't actually a new feature, but at least the thread is giving it some
more exposure. It's been implemented on many browsers for some time already.
I've for example used it for doing quick data-binding. It's really useful and
more people should know about it.

------
Boulth
Proxies are hardly new (2014?), well, just like Es6. There are some
interesting applications [0] but I don't know if is use it in production.

[0]: [https://curiosity-driven.org/array-slices](https://curiosity-
driven.org/array-slices)

------
icc97
> Data persistence. We add a proxy backup function to each object that is
> fired when modifying its content.

This makes me think of database triggers, which would imply that it's quite
easy to implement dark patterns with Proxies.

------
ramadis
I made a simple library to add ruby's `method_missing` to Javascript:
[https://github.com/ramadis/unmiss](https://github.com/ramadis/unmiss)

------
rutierut
Was looking for something exactly like this the other day! No idea this
existed, this will especially be great while stubbing/mocking in tests.

------
foob
Proxies are definitely fun. We use them extensively in our browser automation
framework, which is largely based on the Web Extensions API [1], to implement
syntactic sugar in the interface. The general goal behind Remote Browser [2]
is to make it really easy to execute privileged code in a web browser, but to
otherwise stay out of your way as much as possible. This is accomplished
through the heavy use—some might even say _abuse_ —of proxies.

For instance, take a look at this code example of opening a tab.

    
    
        await browser.evaluateInBackground(createProperties => (
          browser.tabs.create(createProperties)
        ), { url: 'https://intoli.com' });
    

The _browser.evaluateInBackground()_ method is part of the Remote Browser API,
and it simply evaluates code in a background script context in the browser.
The _browser.tabs.create()_ call, on the other hand, is part of the Web
Extensions API. The vast majority of Remote Browser's power is provided
through remote code execution and the Web Extensions API, so we really wanted
to provide a more concise syntax for performing this sort of operation. Using
proxies, we were able to make the _browser_ object directly callable as a
shorthand for background context evaluation. This code example is exactly
equivalent to the previous one.

    
    
        await browser(createProperties => (
          browser.tabs.create(createProperties)
        ), { url: 'https://intoli.com' });
    

That's a bit more concise, but the real sugar is in the next step of
abstraction. Instead of explicitly evaluating a function in the background
script context, you can simply treat the _browser_ object in the client
context as though it were the Web Extensions API _browser_ object in the
background script context. This code example is again exactly equivalent, and
again accomplished using proxies.

    
    
        await browser.tabs.create({ url: 'https://intoli.com' });
    

The _tabs.create_ method isn't hardcoded into the Remote Browser library.
Instead, proxies are used to evaluate any non-local API calls in the
background script context. This means that you automatically get full access
to the version of the Web Extensions API that your browser supports, whether
you're using Chrome, Edge, Firefox, or Opera.

The one last piece of syntactic sugar is the shorthand for evaluating code
inside of individual tabs. The syntax is very similar to how you evaluate
functions in the background script context, you just need to first use square
brackets to indicate the tab ID.

    
    
        await browser[tab.id](createProperties => (
          document.getElementById('some-link').innerHTML
        ), { url: 'https://intoli.com' });
    

This is _also_ implemented using proxies. In fact, the same trap that handles
the local Web Extensions API calls handles the tab access, and it
differentiates between the two depending on whether or not the property name
consists entirely of integers. In both cases, it returns _another_ proxy that
is able to handle either additional chaining or function evaluation.

Anyway, sorry that this ended up a lot more long-winded than I was expecting.
If this has piqued your interest in Remote Browser though, we made an
interactive tour of the project that you should check out [3]. You can
actually launch and control browsers from inside of your own browser in the
tour, and it explains a lot more about the project philosophy and what you can
do with it

[1] - [https://developer.mozilla.org/en-US/Add-
ons/WebExtensions/AP...](https://developer.mozilla.org/en-US/Add-
ons/WebExtensions/API)

[2] - [http://github.com/intoli/remote-
browser/](http://github.com/intoli/remote-browser/)

[3] - [https://intoli.com/tour](https://intoli.com/tour)

------
hguhghuff
I liked the functionality but found it hard to implement. Not a good sign.

Successful features are those that surprise in the easy direction (arrrow
functions) rather than in the hard direction (proxies).

~~~
TomMarius
What were your problems? I on the other hand found it very intuitive.

~~~
hguhghuff
Can’t remember. Maybe I was misusing it. Probably I was trying to either
prevent access to object methods where user not authenticated or prevent
access where object not initialized.

------
rijoja
So this is sort of like metatables in lua?

~~~
wruza
Except that metatable may change the behavior of a table itself, and js proxy
is just a wrapper that cannot change an original object.

~~~
rijoja
ah thanks for clearing that one out

------
celim307
Does es6 tags use this under the hood?

------
hungerstrike
Unfortunately IE doesn't Proxies them at all and you can't even shim support
for them on IE.

