9 ms·
Proxy, a new JavaScript ES6 feature
- syspec 8y agoThe use of `document.write` for this entry instead of the usual console threw me off at first.
- tlrobinson 8y agoPresumably 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 8y agoJSFiddle should just have a tick box with "intercept console.log" and a tab with the output .
- tirthbodawala 8y agoHahahaha...It should!
- icc97 8y agoI initially stared at that with horror, but I suspect that Stack Overflow does something similar with their code snippets. If you write console.log it gets output to the screen [0] [0]: https://stackoverflow.com/a/49968603/327074 https://stackoverflow.com/a/49968603/327074
- tazard 8y agoI feel as though this is a missed opportunity to use a proxy!
- 11235813213455 8y agoI lost it at <?php
- yashthakur 8y agoIt is just because since all the JSFiddles are on one page. All the console.log would be together in the console and it would be difficult to know which console is for which code. Hence document.write is used. Though HTML could be used but that would just increase one more tab to show useless HTML. ;)
- caxco93 8y agoi only made an account to laugh at how the title calls Proxy a "new" feature hahahaaha
- sametmax 8y agoAs 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 8y agoI 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.
- throwaway2016a 8y agoThis is part of the language not just a an interface (though I'm not sure it is an interface, I think it is an object primitive). You wouldn't be able to write this using plain Javascript. Which is why there are no polyfills for client-side code. Incidentally, PHP does it a similar way to Python with so-called "magic methods" but I can see the benefit to doing it this way.
- rijoja 8y agoSo this is sort of like metatables in lua?
- atavkpatel 8y agoWhat is metatables?
- wruza 8y agoExcept that metatable may change the behavior of a table itself, and js proxy is just a wrapper that cannot change an original object.
- rijoja 8y agoah thanks for clearing that one out
- techsin101 8y agoThis is another feature that goes into bucket "I'll never use" along generators
- augbog 8y agoWell technically if you use async / await, it's built on top of generators and promises.
- CapacitorSet 8y agoI agree it doesn't seem super useful, but it can be used to pull some semantic tricks. I used it in [Rebridge](https://github.com/CapacitorSet/rebridge/ https://github.com/CapacitorSet/rebridge/) to implement syntactic sugar for database access, so that accessing a property on an object translates transparently to a query, and I've seen it used to [allow for typos in property names](https://github.com/mathiasbynens/tpyo https://github.com/mathiasbynens/tpyo).
- yashthakur 8y agoI especially liked the "construct" part as we can use it to take input from the users in frontend as a numbered value and then store it in the database with the currency format which can be later used to make the value visible with the currency in the frontend.
- sametmax 8y agoGenerators 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.
- 8y ago
- celim307 8y agoDoes es6 tags use this under the hood?
- hackerbabz 8y agoWhy is this an ES6 feature? Isn't ES6 set and implemented? Wouldn't this be part of a future spec (ES2018, ES2019, or whatever)?
- rf15 8y agoIt's an existing, rarely-used feature. You can try it in your browser!
- TomMarius 8y agoBecause it is not a future feature, it exists for years now (I first used it in 2016).
- taco_emoji 8y agohttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy#Browser_compatibility https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe... 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
- jazoom 8y agoIt's a poor title. It's not your fault.
- hguhghuff 8y agoI 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).
- matsemann 8y agoI 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 8y agoHaha that's a hilarious abomination :) It's a shame it doesn't have declaraoids.makeMeASandwich() on the roadmap though.
- throwaway2016a 8y agoYou 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.html#findby https://book.cakephp.org/2.0/en/models/retrieving-your-data....
- twic 8y agoAlso Java's Spring Data: https://docs.spring.io/spring-data/commons/docs/current/reference/html/#repositories.query-methods.query-creation https://docs.spring.io/spring-data/commons/docs/current/refe... Wasn't it an ActiveRecord thing to begin with? Spring got a lot of its more recent awful features by trying to copy Rails.
- rutierut 8y agoWas looking for something exactly like this the other day! No idea this existed, this will especially be great while stubbing/mocking in tests.
- sgdesign 8y agoI 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.
- philbo 8y agoA 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/61087c194d5675c75569a2e08617a98609b16ead/src/match.js#L197-L201 https://github.com/philbooth/bfj/blob/61087c194d5675c75569a2...
- lioeters 8y agoA circular array type, love it! It looks like an excellent use case of proxies.
- flashgordon 8y agoTechnically the type should still be an Array with the backing implementation having a circular array behavior no?
- lioeters 8y agoIndeed, it extends native Array: https://github.com/philbooth/hoopy/blob/master/index.js#L3 https://github.com/philbooth/hoopy/blob/master/index.js#L3
- antoaravinth 8y agoCool. I was seeing source of inner js, which in deed uses proxies to create structural sharing. https://github.com/mweststrate/immer https://github.com/mweststrate/immer
- foob 8y agoProxies 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/API https://developer.mozilla.org/en-US/Add-ons/WebExtensions/AP... [2] - http://github.com/intoli/remote-browser/ http://github.com/intoli/remote-browser/ [3] - https://intoli.com/tour https://intoli.com/tour
- kevincennis 8y agoProxies 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/25ba31b2e9f9c8b7a34047ba0108aff0 https://gist.github.com/kevincennis/25ba31b2e9f9c8b7a34047ba...
- icc97 8y ago> 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.
- fergie 8y agoThis 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/Reference/Global_Objects/Proxy https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...) 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 8y agoYou 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 8y agoYou 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 8y agoOne 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.
- isuckatcoding 8y agohttps://caniuse.com/#feat=proxy https://caniuse.com/#feat=proxy Seems to have a decent coverage for most users
- throwaway2016a 8y agoThe 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 8y agoYou 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 8y agoYou 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 8y agoAh 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.
- sfa_aok 8y agoSalesforce 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 8y agoEverything 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.
- dlhavema 8y agoThe biggest thing that gets me when my coworkers do SF dev is how many times they have to refresh to see the new code. Its almost always two or three. Ive seen the proxy thing trying to debugging. I didn't realize it was a set pattern/language feature.
- haikuginger 8y agoThis 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
- liberatus 8y agoBig win for JavaScript DSL composers. Reminds me of method_missing and other sharp knives in ruby.
- SimeVidas 8y agoI’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 8y agoI 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.
- 13years 8y agoI 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
- ramadis 8y agoI made a simple library to add ruby's `method_missing` to Javascript: https://github.com/ramadis/unmiss https://github.com/ramadis/unmiss
- loftyal 8y agoAnyone using redux, I created this using proxies - https://github.com/alnorris/redux-actiontyper https://github.com/alnorris/redux-actiontyper
- _bxg1 8y agoProxies 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 8y agoCool 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
- nathanstitt 8y agoI 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.
- hungerstrike 8y agoUnfortunately IE doesn't Proxies them at all and you can't even shim support for them on IE.
- cwp 8y agoI 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.
- caxco93 8y agoThis 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.
- jaequery 8y agoI'm not really a fan of these "magic" code creators. I'd use it only as required and not all out.
- Boulth 8y agoProxies 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
- colept 8y agoProxy 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.
- Too 8y agoI 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.
- lindellme 8y agoI made use of Proxies in a new project where you can seamlessly call functions on other node services as if they were located at the local machine. https://github.com/lindell/remote-function https://github.com/lindell/remote-function