ES6 Symbols



In this post I will discuss Symbol.hasInstance which is the first of 11 well-known symbols provided by the ES6 specification. Well-known symbols, for those unfamiliar, are provided by JavaScript as properties on an object which let you re-configure how ES6 treats the object. We will see how they are used in a minute.

Which native functions make use of Symbol.hasInstance?

The short answer is that the native instanceof function holds the sole rights to Symbol.hasInstance. Symbol.hasInstance in turn lets you customize and modify the behavior of the instanceof method. Let’s review the basics of instanceof briefly…

How is instanceof implemented?

instanceof is a method available to nearly every function. Objects in JavaScript are linked via a prototype chain. Therefore a method that is a metaphorical “child” of its parent does not inherit the properties of the parent but rather contains a link to the parent’s prototype. As such, instanceof compares the left-hand of its operand to the right-hand and determines if in the entire prototype chain of the left side, does the right-side’s prototype appear. It does this by querying the property Symbol.hasInstance placed on the prototypes of Objects.

instanceof‘s low-level implementation is via a Symbol.hasInstance property placed on native functions of an Object. Symbol.hasInstance is referred to as @@hasInstance for short in the ES6 spec. To implement instanceof , child instanceof parent evaluates according to the spec to parent[@@hasInstance](child) and when reduced further essentially evaluates to parent[Symbol.hasInstance](child).  So in short instanceof behind the scenes is implemented through querying the property Symbol.hasInstance which happens to be the topic of this post. instanceof is actually the only native function to make use of Symbol.hasInstance.

Here is a piece describing what we just discussed from the ES6 spec:

This (i.e. Function.prototype[@@hasInstance](V)) is the default implementation of @@hasInstance that most functions inherit. @@hasInstance is called by the instanceof operator to determine whether a value is an instance of a specific constructor. An expression such as
v instanceof F
evaluates as
. . . . . .
The value of the name property of this function (i.e. @@hasInstance) is "[Symbol.hasInstance]".

Note: I know there is a trend to use Object.create() instead of new; however, this will not work as intended with instanceof since the left-side of instanceof is intended to be an object and the right-side a function. The Object.create() design pattern means that both the left and right-side will be objects which throws an error. If you plan on using instanceof stick to function name() and new instantiation as in the examples in this post. Here’s an example of the error thrown with the Object.create() design pattern.

What are some use cases for Symbol.hasInstance?

Here are two examples, the first is basic and less useful while the second is a more practical application…

I can’t say those examples are extremely practical, but it’s nice to know how to overwrite Symbol.hasInstance. If you have a more practical use-case please comment below!

Exploiting Symbol.hasInstance for malicious purposes

Symbol.hasInstance is a powerful property and one that can be exploited for nefarious purposes. Let’s explore how to exploit Symbol.hasInstance to expose the scope of private functions, and also how to modify instanceof to always return true.

Unfortunately for the black-hatters among us, ECMAScript figured out this exploit before it was released and made Function.prototype[Symbol.hasInstance] non-writable and non-configurable. So says the spec:

This property (referring to Function.prototype[Symbol.hasInstance]) is non-writable and non-configurable to prevent tampering that could be used to globally expose the target function of a bound function.

This makes using Object.defineProperty() to redefine Function.prototype throw TypeError: Cannot redefine property: Symbol(Symbol.hasInstance) saving the day and countless code!

That’s it for now. There’s plenty more to write regarding the use of Object.setPrototypeOf and Object.getPrototypeOf instead of and perhaps preferable to instanceof. There’s also potentially more to add regarding prototypes in general. Perhaps I’ll add those as another post or tack on to this one!

Thanks for reading!

Josh Miller

Josh Miller Josh Miller

I’m a full-stack web developer who’s especially enthusiastic about the rapid developments in JavaScript. I’ve created this blog as a medium to share with others a journey of knowledge and discovery.

No Comments

Leave a comment