New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES5 shim for proxies #8

Open
ghost opened this Issue Jun 27, 2012 · 1 comment

Comments

Projects
None yet
1 participant
@ghost

ghost commented Jun 27, 2012

I've been exploring various concepts for trying to bring ES6 features to ES5 supporting engines (without source rewriting). One example is of bringing Names to ES5 (http://bbenvie.com/articles/2012-06-06/ES6-Private-Names-Shim), and collections (https://github.com/Benvie/ES6-Harmony-Collections-Shim) are trivial to implement at an API compatible level and many other features are as well. Obviously anything related to syntax changes are out. Proxies represent an interesting in between, where the syntax is fully compatible but the underlying semantics are...complicated.

In fact, it's trivial to shim most of the features of proxies as this very repo shows. The direct proxy concept is implemented on top of the original proxy api almost entirely (from a user standpoint) due to the fact that almost all of the operations in JS are already only accessible via function calls, and some of the ones that aren't still defer to JS code anyway (toString, valueOf). The only ones that are non-obvious to shim are the literal operations: get, set, delete, has, in. Using ES5 and premeditation, you can even handle get and set for existing properties.

I don't have answers to this but I thought it could potentially be in the spirit of this specific project.

@tvcutsem

This comment has been minimized.

Show comment
Hide comment
@tvcutsem

tvcutsem Jun 27, 2012

Owner

I have had similar thoughts. In particular, your point about trapping the existing properties of an object on an ES5 engine without any support for proxies.

The reason I haven't pursued this is that the emulation would be woefully incomplete: you'd be able to trap property "get", "set" and function "apply" of existing properties but that's pretty much it (apart from all the Object.* methods of course, but those are not the commonly used operations). If properties are added to the target object after the proxy is created, those won't get trapped. Similarly, we wouldn't be able to trap "in", "delete" and "for-in", and only unreliably trap "new". All in all, I think there would just be too many missing features to be a usable/reliable shim.

However, it's nice to know that the Reflect API (excluding Proxy and VirtualHandler) is shimmable in ES5. Most of these methods are really just a thin wrapper around things easily done in pure ES5, but some methods do offer some added benefit:

  • Reflect.get and Reflect.set can be used to forward property access/update with a specific |this|-binding for accessors
  • Reflect.set returns a boolean to indicate success, as opposed to obj[name] = val which does not
  • Reflect.deleteProperty, Reflect.freeze, Reflect.seal and Reflect.preventExtensions all return a boolean to indicate success, as opposed to their direct ES5 counterparts.
  • Reflect.construct can be used to do new Function(...args), which is hard-to-do in pure ES5 given the lack of the spread-operator
  • Reflect.apply(fun, self, args) is shorter to write (and easier to understand) than Function.prototype.apply.call(fun, self, args) in cases where we can't reliably write fun.apply(self, args).
Owner

tvcutsem commented Jun 27, 2012

I have had similar thoughts. In particular, your point about trapping the existing properties of an object on an ES5 engine without any support for proxies.

The reason I haven't pursued this is that the emulation would be woefully incomplete: you'd be able to trap property "get", "set" and function "apply" of existing properties but that's pretty much it (apart from all the Object.* methods of course, but those are not the commonly used operations). If properties are added to the target object after the proxy is created, those won't get trapped. Similarly, we wouldn't be able to trap "in", "delete" and "for-in", and only unreliably trap "new". All in all, I think there would just be too many missing features to be a usable/reliable shim.

However, it's nice to know that the Reflect API (excluding Proxy and VirtualHandler) is shimmable in ES5. Most of these methods are really just a thin wrapper around things easily done in pure ES5, but some methods do offer some added benefit:

  • Reflect.get and Reflect.set can be used to forward property access/update with a specific |this|-binding for accessors
  • Reflect.set returns a boolean to indicate success, as opposed to obj[name] = val which does not
  • Reflect.deleteProperty, Reflect.freeze, Reflect.seal and Reflect.preventExtensions all return a boolean to indicate success, as opposed to their direct ES5 counterparts.
  • Reflect.construct can be used to do new Function(...args), which is hard-to-do in pure ES5 given the lack of the spread-operator
  • Reflect.apply(fun, self, args) is shorter to write (and easier to understand) than Function.prototype.apply.call(fun, self, args) in cases where we can't reliably write fun.apply(self, args).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment