As we learned from the earlier lesson, reflection represents introspection, intercession, and modification of the program. Prior to ES2015 (ES6), we had a few tools available to us to introspect and modify the behavior of the program such as Object.keys
or instanceof
operator among many.
In ES2015, we received a [Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)
global object that provides some pretty useful methods for metaprogramming. Like [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math)
and [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON)
objects, Reflect
is not a function nor it’s constructible. Its only job is to provide static methods for reflection. These methods can be divided into two categories.
Introspection methods are non-destructive methods. They are only used to introspect objects. Modification methods are destructive since they mutate the object or its behavior. Most of these methods are derived from old JavaScript implementations and we will talk about this as well.
In the earlier lesson, we took a quick look at the [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
class which is used to intercept object operations. Proxy
handler methods and Reflect
static methods share the same function signature. We will talk more about this in the Proxy lesson (coming soon) but let’s discuss briefly why these method signatures are the same. For that, we need to look inside ECMAScript specifications.
The 6.1.7.2 section of the ECMAScript 2015 specification talks about some weird internal properties and internal methods objects (_descendants of __Object_
) can have. These properties or methods are implemented by the JavaScript engine but they are abstracted away from the runtime, hence you won’t be able to access them on the objects like normal properties.
These are represented by the [[<name>]]
notation in the ECMAScript specification where name
is the name of the internal property or internal method. The internal property is called an internal slot and it contains a value associated with that object to represent some state of the object.
Let’s take a quick example. The [[GetPrototypeOf]]
internal method is implemented by all the objects and its job is to return the prototype of the object. When you execute Reflect.getPrototypeOf(_obj_)
method with obj
being the object whose prototype needs to be inspected, JavaScript engine calls the [[GetPrototypeOf]]
internal method of the obj
which returns the value of [[Prototype]]
internal slot of the object that contains the prototype.
💡 The
_obj.__proto___
also points to the prototype of the_obj_
and accessing it would be like accessing the_[[Prototype]]_
internal slot of the_obj_
.
When an internal method is invoked on an object such as obj
in the above example, it is called the “target” of the invocation. If the target doesn’t support an internal method, for example calling the Reflect.getPrototypeOf
on null
, a TypeError
exception is thrown.
Objects can have multiple internal slots and internal methods. ECMAScript specification does not describe how these internal methods are implemented but it describes the signature of the method call. The following are ES2015 internal methods implemented by all objects (hence essential). These internal methods may accept some arguments of specific ECMAScript language types and may return a value
#es6 #ecmascript-6 #metaprogramming #javascript #ecmascript