Metaprogramming with ES6
So expression like this:
Would work pretty much everywhere where you can execute JS (there are some exceptions though). This is very handy when it comes to hacking, but you shouldn’t really rely on it when developing real-life applications.
First thing that TC39 brought us is a new data type called Symbol. Symbols are unique. Symbols are immutable. Symbols are amazing. It’s useful to know how Symbols work and what exactly they can be used for, since they can be a really powerful weapon in your hands.
So let’s start from the very beginning. Do you remember what I’ve just said? Symbols are unique. I mean really unique.
Ok, but what about that? A symbol is a unique and immutable data type. Its new primitive which can be used as object keys just like strings. Example below will illustrate this uniqueness better:
Huh — that can be useful, right? If you didn’t notice, we can define keys which look the same but are completely unique. That’s a big advantage when it comes to hacking. But this is not the last thing that Symbols bring us.
If you started your journey with programming with a different language, then you would probably wonder how to implement private fields in JS class. Well — Symbols can help you achieve a similar thing. Why similar? Because the information is still accessible, but not really visible at first glance. Let’s take a look at the example below:
In this case, your ‘crazy’ Symbol won’t be visible until you call Object.getOwnProperties() on your instance. That’s pretty handy when you don’t want to expose internal details.
Another useful constant is Symbol.hasInstance. It can be used to change the mechanics of the instanceof operator. We can easily specify if a given variable is an instance of our class. We don’t even need to extend the class in any way, just specify a static [Symbol.hasInstance] function and enjoy the result.
Symbols are very useful if you want to do something differently within String methods. If you need String.match(), String.replace() or String.search() to provide you a different result, then you can pick between Symbol.match, Symbol.replace and Symbol.search. I’ll just show you how usage of the last one can be implemented.
There is much more to learn about Symbols. But since it’s not the only feature i want to show you today, I’ll send you back to mozilla docs.
6th edition of EcmaScript brings us a new built-in object called Reflect from Reflection API. You cannot create a new instance of Reflect, but it exposes a few handy methods which can be used to reveal information about objects and provide some nice syntax sugar for old methods.
If you had read this article carefully, you would have probably noticed that thanks to symbols we can hide some of the information about an object at first glance. Reflect objects can help us discover some lower-level information about an object and all its properties and symbols with just one function.
As you can see, we can discover all of the information about an object (including its symbols). You can think of this method as a mixture of Object.getOwnPropertyNames() and Object.getOwnPropertySymbols().
Have you ever used Object.create() ? It’s a method used to create instances of an object. But it has its pitfalls — what if we want to create an instance and call the class constructor with our new argument? Then we should probably consider using Object.call().
Yeah — almost everything is achievable, but why not make it easy. Just watch how easily we can construct a new date with Reflect compared to old Object’s way.
As we’ve just seen how to create an object with Reflect, now it’s time to do some damage to objects. We can use our new friend to delete the object property. Simply call Reflect.deleteProperty() and free your object from unwanted props.
If you know JS’s delete operator then it’s almost identical, but Reflect.deleteProperty() ignores type checking and works only for objects, not for any kind of variable.
Everything we just learned about Reflect is related to Objects — but it also provides some improvements over Function’s .call() and .apply(). Now, instead of calling both those functions over your function, you can simply use Reflect.apply(). It’s a really nice piece of syntax sugar over chaining those two. Just watch.
As you can see, the width persisted through deletion. That’s quite a powerful property when it comes to modifying default behavior.