I saw a blank stub on MDN a while ago for the Reflect
object in javascript but I can't for the life of me find anything on Google. Today I found this http://people.mozilla.org/~jorendorff/es6-draft.html#sec-reflect-object and it sounds similar to the Proxy object apart from the realm and loader functionality.
Basically, I don't know whether this page I found only explains how to implement Reflect or if I just can't understand its wording. Could someone please explain to me generally what the methods of Reflect
do?
For instance, on the page I found says that calling Reflect.apply ( target, thisArgument, argumentsList )
will "Return the result of calling the [[Call]] internal method of target with arguments thisArgument and args." but how is that any different than just calling target.apply(thisArgument, argumentsList)
?
Update:
Thanks to @Blue, I found this page on the wiki http://wiki.ecmascript.org/doku.php?id=harmony:reflect_api&s=reflect which to the best of my knowledge says that the reflect object provides method versions of all the actions that can be trapped by proxies to make forwarding easier. But that seems a little weird to me since I don't see how it's entirely necessary. But it Seems to do a little more than that, particularly the par that says double-lifting
but that points to the old proxy spec/
UPDATE 2015: As pointed out by 7th's answer, now that ES6 (ECMAScript 2015) has been finalized, more appropriate documentation is now available:
The Reflection proposal
seems to have progressed to the Draft ECMAScript 6 Specification. This document currently outlines the Reflect
-object's methods and only states the following about the Reflect
-object itself:
The Reflect object is a single ordinary object.
The value of the [[Prototype]] internal slot of the Reflect object is the standard built-in Object prototype object (19.1.3).
The Reflect object is not a function object. It does not have a [[Construct]] internal method; it is not possible to use the Reflect object as a constructor with the new operator. The Reflect object also does not have a [[Call]] internal method; it is not possible to invoke the Reflect object as a function.
However, there is a short explanation about it's purpose in ES Harmony:
The “@reflect” module serves multiple purposes:
- Now that we have modules, a “@reflect” module is a more natural place for many of the reflection methods previously defined on Object. For backwards-compatibility purposes, it is unlikely that the static methods on Object will disappear. However, new methods should likely be added to the “@reflect” module rather than to the Object constructor.
- A natural home for proxies, avoiding the need for a global Proxy binding.
- Most methods in this module map one-to-one onto Proxy traps. Proxy handlers need these methods to conveniently forward operations, as shown below.
So, the Reflect
object provides a number of utility functions, many of which appear to overlap with ES5 methods defined on the global Object.
However, that doesn't really explain what existing problems this intends to solve or what functionality is added. I suspected this could be shimmed and indeed, the above harmony-spec links to a 'non-normative, approximate implementation of these methods'.
Examining that code could give (further) idea's about it's use, but thankfully there is also a wiki that outlines a number of reasons why the Reflect object is useful:
(I've copied (and formatted) the following text for future reference from that source as they are the only examples I could find. Besides that, they make sense, already have a good explanation and touch the question's apply
example.)
More useful return values
Many operations in Reflect
are similar to ES5 operations defined on Object
, such as Reflect.getOwnPropertyDescriptor
and Reflect.defineProperty
. However, whereas Object.defineProperty(obj, name, desc)
will either return obj
when the property was successfully defined, or throw a TypeError
otherwise, Reflect.defineProperty(obj, name, desc)
is specced to simply return a boolean that indicates whether or not the property was successfully defined. This allows you to refactor this code:
try { Object.defineProperty(obj, name, desc); // property defined successfully } catch (e) { // possible failure (and might accidentally catch the wrong exception) }
To this:
if (Reflect.defineProperty(obj, name, desc)) { // success } else { // failure }
Other methods that return such a boolean success status are Reflect.set
(to update a property), Reflect.deleteProperty
(to delete a property), Reflect.preventExtensions
(to make an object non-extensible) and Reflect.setPrototypeOf
(to update an object's prototype link).
First-class operations
In ES5, the way to detect whether an object obj
defines or inherits a certain property name is to write (name in obj)
. Similarly, to delete a property, one uses delete obj[name]
. While dedicated syntax is nice and short, it also means you must explicitly wrap these operations in functions when you want to pass the operation around as a first-class value.
With Reflect
, these operations are readily defined as first-class functions:Reflect.has(obj, name)
is the functional equivalent of (name in obj)
and Reflect.deleteProperty(obj, name)
is a function that does the same as delete obj[name].
More reliable function application
In ES5, when one wants to call a function f
with a variable number of arguments packed as an array args
and binding the this
value to obj
, one can write:
f.apply(obj, args)
However, f
could be an object that intentionally or unintentionally defines its own apply
method. When you really want to make sure that the built-in apply
function is called, one typically writes:
Function.prototype.apply.call(f, obj, args)
Not only is this verbose, it quickly becomes hard to understand. With Reflect
, you can now make a reliable function call in a shorter and easier to understand way:
Reflect.apply(f, obj, args)
Variable-argument constructors
Imagine you want to call a constructor function with a variable number of arguments. In ES6, thanks to the new spread syntax, it will be possible to write code like:
var obj = new F(...args)
In ES5, this is harder to write, because one can only use F.apply
or F.call
to call a function with a variable number of arguments, but there is no F.construct
function to new
the function with a variable number of arguments. With Reflect
, one can now write, in ES5:
var obj = Reflect.construct(F, args)
Default forwarding behavior for Proxy traps
When using Proxy
objects to wrap existing objects, it is very common to intercept an operation, do something, and then to "do the default thing", which is typically to apply the intercepted operation to the wrapped object. For example, say I want to simply log all property accesses to an object obj
:
var loggedObj = new Proxy(obj, { get: function(target, name) { console.log("get", target, name); // now do the default thing } });
The Reflect
and Proxy
APIs were designed in tandem, such that for each Proxy
trap, there exists a corresponding method on Reflect
that "does the default thing". Hence, whenever you find yourself wanting to "do the default" thing inside a Proxy handler, the correct thing to do is to always call the corresponding method in the Reflect
object:
var loggedObj = new Proxy(obj, { get: function(target, name) { console.log("get", target, name); return Reflect.get(target, name); } });
The return type of the Reflect
methods is guaranteed to be compatible with the return type of the Proxy
traps.
Control the this-binding of accessors
In ES5 it's fairly easy to do a generic property access or property update. For instance:
var name = ... // get property name as a string obj[name] // generic property lookup obj[name] = value // generic property update
The Reflect.get
and Reflect.set
methods allow you to do the same thing, but additionally accept as a last optional argument a receiver
parameter that allows you to explicitly set the this
-binding when the property that you get/set is an accessor:
var name = ... // get property name as a string Reflect.get(obj, name, wrapper) // if obj[name] is an accessor, it gets run with `this === wrapper` Reflect.set(obj, name, value, wrapper)
This is occasionally useful when you're wrapping obj
and you want any self-sends within the accessor to get re-routed to your wrapper, e.g. if obj
is defined as:
var obj = { get foo() { return this.bar(); }, bar: function() { ... } }
Calling Reflect.get(obj, "foo", wrapper)
will cause the this.bar()
call to get rerouted to wrapper
.
Avoid legacy __proto__
On some browsers, __proto__
is defined as a special property that gives access to an object's prototype. ES5 standardized a new method Object.getPrototypeOf(obj)
to query the prototype. Reflect.getPrototypeOf(obj)
does exactly the same, except that Reflect
also defines a corresponding Reflect.setPrototypeOf(obj, newProto)
to set the object's prototype. This is the new ES6-compliant way of updating an object's prototype.
Note that: setPrototypeOf
also exists on Object
(as correctly pointed out by Knu's comment)!
EDIT:
Side-note (addressing comments to the Q): There is a short and simple answer on 'Q: ES6 Modules vs. HTML Imports' that explains Realms
and Loader
objects.
Another explanation is offered by this link:
A realm object abstracts the notion of a distinct global environment, with its own global object, copy of the standard library, and "intrinsics" (standard objects that are not bound to global variables, like the initial value of Object.prototype).
Extensible web: This is the dynamic equivalent of a same-origin
<iframe>
without DOM.
Worth mentioning though: all this is still in draft, this is not a specification etched in stone! It's ES6, so keep browser-compatibility in mind!
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With