METAPROGRAMMING IN JAVASCRIPT

Introduction to “Reflect” API for Metaprogramming in JavaScript

In this lesson, we are going to learn about the `Reflect` global object available in the ES2015+. It provides various static functions to introspect and modify JavaScript objects.

Uday Hiwarale
Aug 15, 2020 · 13 min read
(source: unsplash.com)

Object Internal Methods and Internal Slots

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.

Introspection Methods

These methods are purely used for introspection purpose and they do not modify the object, its behavior, or its internal state.

● Reflect.get

Reflect.get(target, propertyKey[, receiver])
(reflect/get.js)
Reflect.get( null, 'prop' )
Reflect.get( 'hello', 'length' )
// TypeError: Reflect.get called on non-object

● Reflect.has

Reflect.has(target, propertyKey)
(reflect/has.js)
Reflect.has( null, 'prop' )
Reflect.has( 'hello', 'length' )
// TypeError: Reflect.has called on non-object

● Reflect.ownKeys

Reflect.ownKeys(target)
(reflect/ownKeys.js)
Reflect.ownKeys( null )
Reflect.ownKeys( 'hello' )
// TypeError: Reflect.ownKeys called on non-object

● Reflect.getOwnPropertyDescriptor

Reflect.getOwnPropertyDescriptor(target, propertyKey)
(reflect/getOwnPropertyDescriptor.js)
Reflect.getOwnPropertyDescriptor( null, 'prop' )
Reflect.getOwnPropertyDescriptor( 'hello', 'length' )
// TypeError: Reflect.getOwnPropertyDescriptor called on non-object
Object.getOwnPropertyDescriptor( null )
// TypeError: Cannot convert undefined or null to object
Object.getOwnPropertyDescriptor( 'hello', 'length' )
// {value: 5, writable: false, enumerable: false, …}
Object.getOwnPropertyDescriptor( {}, 'prop' )
// undefined

● Reflect.getPrototypeOf

Reflect.getPrototypeOf(target)
(reflect/getPrototypeOf.js)
Reflect.getPrototypeOf( null )
Reflect.getPrototypeOf( 'hello' )
// TypeError: Reflect.getPrototypeOf called on non-object
Object.getPrototypeOf( null )
// TypeError: Cannot convert undefined or null to object
Object.getPrototypeOf( 'hello' )
// String {constructor: String(), anchor: ƒ, big: ƒ, …}
Object.getPrototypeOf( {} )
// Object {constructor: Object(), __defineGetter__: ƒ, …}

● Reflect.isExtensible

Reflect.isExtensible(target)
(reflect/isExtensible.js)
Reflect.isExtensible( null )
Reflect.isExtensible( 'hello' )
// TypeError: Reflect.isExtensible called on non-object
Object.isExtensible( null )
// false
Object.isExtensible( 'hello' )
// false
Object.isExtensible( {} )
// true

Modification Methods

These methods modify the target value or its behavior, or its internal state.

● Reflect.deleteProperty

Reflect.deleteProperty(target, propertyKey)
(reflect/deleteProperty.js)
Reflect.deleteProperty( null, 'prop' )
Reflect.deleteProperty( 'hello', 'length' )
// TypeError: Reflect.deleteProperty called on non-object

● Reflect.set

Reflect.set(target, propertyKey, value[, receiver])
(reflect/set.js)
Reflect.set( null, 'prop', 'val' )
Reflect.set( 'hello', 'length', 2 )
// TypeError: Reflect.set called on non-object

● Reflect.defineProperty

Reflect.defineProperty(target, propertyKey, descriptor)
(reflect/defineProperty.js)
Reflect.defineProperty( null, 'prop', {value: 2})
Reflect.defineProperty( 'hello', 'length', {value: 3})
// TypeError: Reflect.defineProperty called on non-object

● Reflect.preventExtensions

Reflect.preventExtensions(target)
(reflect/preventExtensions.js)
Reflect.preventExtensions( null )
Reflect.preventExtensions( 'hello' )
// TypeError: Reflect.preventExtensions called on non-object
Object.preventExtensions( null )
// false
Object.preventExtensions( 'hello' )
// 'hello'
Object.preventExtensions( {name: 'ross'} )
// {name: 'ross'}

● Reflect.setPrototypeOf

Reflect.setPrototypeOf(target, prototype)
var obj = Object.preventExtensions({});
Reflect.setPrototypeOf(obj, null);
// false
Reflect.setPrototypeOf({}, "")
Reflect.setPrototypeOf(function(){}, "")
// TypeError: Object prototype may only be an Object or null
(reflect/setPrototypeOf.js)
Reflect.setPrototypeOf( null, null )
Reflect.setPrototypeOf( 'hello', null )
// TypeError: Reflect.setPrototypeOf called on non-object
Object.setPrototypeOf( null, null )
// TypeError: Object.setPrototypeOf called on null or undefined
Object.setPrototypeOf( Object.preventExtensions({}), null )
// TypeError: #<Object> is not extensible
Object.setPrototypeOf( {name: 'ross'}, "")
// TypeError: Object prototype may only be an Object or null
Object.setPrototypeOf( {name: 'ross'}, null )
// {name: 'ross'}

● Reflect.apply

Reflect.apply(target, thisArgument, argumentsList)
let func = ( ...args ) => console.log(args);func.apply(null, undefined)
func.apply(null, null)
func.apply(null, {})
// []
func.apply(null, "")
// TypeError: CreateListFromArrayLike called on non-object
func.apply(null, [1, 2, 3])
// [1, 2, 3]
Reflect.apply(func, null, undefined)
Reflect.apply(func, null, null)
Reflect.apply(func, null, "")
// TypeError: CreateListFromArrayLike called on non-object
Reflect.apply(func, null, {})
// []
▶ Reflect.apply(func, null, [1, 2, 3])
// [1, 2, 3]
Reflect.apply( null, null, [] )
// TypeError: Function.prototype.apply was called on null, which is a object and not a function
Reflect.apply( 'hello', null, [] )
// TypeError: Function.prototype.apply was called on hello, which is a string and not a function
Reflect.apply( {}, null, [] )
// TypeError: Function.prototype.apply was called on #<Object>, which is a object and not a function

● Reflect.construct

Reflect.construct(target, argumentsList[, newTarget])
let instance = Object.create( newTarget.prototype )
target.apply( instance, argumentsList );
let instance = Object.create( target.prototype )
target.apply( instance, argumentsList );
(reflect/construct.js)
Reflect.construct( {}, [] )
// TypeError: #<Object> is not a constructor
Reflect.construct( Symbol, [] )
// TypeError: Symbol is not a constructor
Reflect.construct( null, [] )
// TypeError: null is not a constructor
Reflect.construct( Object, [], Symbol )
// Symbol {}
Reflect.construct( Object, [], Reflect )
Reflect.construct( Object, [], Math )
Reflect.construct( Object, [], JSON )
// TypeError: #<Object> is not a constructor

JsPoint

JavaScript and the Web

Uday Hiwarale

Written by

Software Engineer at kausa.ai / thatisuday.com ☯ github.com/thatisuday ☯ thatisuday@gmail.com

JsPoint

JsPoint

A collection of essential articles for JavaScript, WebAssembly, TypeScript, Node.js, Deno, and Web development in general.

Uday Hiwarale

Written by

Software Engineer at kausa.ai / thatisuday.com ☯ github.com/thatisuday ☯ thatisuday@gmail.com

JsPoint

JsPoint

A collection of essential articles for JavaScript, WebAssembly, TypeScript, Node.js, Deno, and Web development in general.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store