Meta Properties

In the “new.target“ section of Chapter 3, we introduced a concept new to JS in ES6: the meta property. As the name suggests, meta properties are intended to provide special meta information in the form of a property access that would otherwise not have been possible.

In the case of new.target, the keyword new serves as the context for a property access. Clearly new is itself not an object, which makes this capability special. However, when new.target is used inside a constructor call (a function/method invoked with new), new becomes a virtual context, so that new.target can refer to the target constructor that new invoked.

This is a clear example of a meta programming operation, as the intent is to determine from inside a constructor call what the original new target was, generally for the purposes of introspection (examining typing/structure) or static property access.

For example, you may want to have different behavior in a constructor depending on if it’s directly invoked or invoked via a child class:

  1. class Parent {
  2. constructor() {
  3. if (new.target === Parent) {
  4. console.log( "Parent instantiated" );
  5. }
  6. else {
  7. console.log( "A child instantiated" );
  8. }
  9. }
  10. }
  11. class Child extends Parent {}
  12. var a = new Parent();
  13. // Parent instantiated
  14. var b = new Child();
  15. // A child instantiated

There’s a slight nuance here, which is that the constructor() inside the Parent class definition is actually given the lexical name of the class (Parent), even though the syntax implies that the class is a separate entity from the constructor.

Warning: As with all meta programming techniques, be careful of creating code that’s too clever for your future self or others maintaining your code to understand. Use these tricks with caution.