Rémy Adzuar's Develop Blog!

You need to discover new.target propertie

If you are a Javascript developper, and you don't know or you only know one usage of new.target constructor propertie, you absolutely need to discover more deeply usage of this propertie.

Here I will only speak deeply the use I have made to enforce abstract classes

Enforce a class as abstract

You know, javascript is a cool guys, and define an abstract class for him is just, define a class that we can extend in other classes.

But with new.target, you can enforce that the abstract don't allow to be instantiate in itself! Let's see that :


class AbstractClass {
    constructor() {
        if (new.target === AbstractClass) {
            throw new Error('Cannot instantiate abstract class directly');
        }
        

So with this build, if the class is wrongly directly instanciate, an error is throw and Voilà, we could no longer instanciate the abstract class!

My use :

I'm kind of hobbyist of trying and failling to reproduce games of my childhood... One of these is Sid Meir's Civlization. Ho I will not trying to guess how many hours on Civ II and sucessor's I spendt.

In these game, you had a map, and lot of actions possible. In javascript you can easily handle event by :

            
                document.addEventListener('click', (event) => {
                    console.log(event);
                });
            
        

And when it's done, you could also easily get the Html element targetted, like a cell in a table :

            
                document.addEventListener('click', (event) => {
                    const target = event.target;
                    console.log(target);
                });
            
        

Pretty simple isn't. But when we complexify a bit the number of interaction, it could rapidly become a ball of mud to manage, so classically I implement a StateManager.

This pattern is really simple, we had a class StateManager, that has a propertie "state" that will point into an instance of a class that implements the current state (e.g : a state could be "moving unit", "select case on map", "manage a city").

Another major point is that StateManager listen for events (like clicks and keypress) and pass the event the current state method. And that's like this that we can implements as many behavior we want.

            
class StateManager {
    constructor() {
        this.state = null;
    }
    setState(state) {
        this.state = state;
    }
    handleEvent(event) {
        if (this.state) {
            this.state.handleEvent(event);
        }
    }
}
class State {
    constructor(stateManager) {
        if (new.target === State) {
            throw new Error('Cannot instantiate abstract class directly');
        }
        this.stateManager = stateManager;
    }
    handleEvent(event) {
        throw new Error('handleEvent() must be implemented in subclass');
    }
}
class MovingUnitState extends State {
    constructor(stateManager) {
        this.name = 'MovingUnitState';
        super(stateManager);
    }
    handleEvent(event) {
        if (event.type === 'click') {
            // Handle click event for moving unit
            const target = event.target;
            console.log(`Moving unit to ${target}`);
        }
    }
}
            
        

And tada, now you see that in the State constructor definition we enforce that this class cannot be directly instanciate, the new.target need to be different from "State" to not throwing errors.

Of course we have some other usage for new.target, I resume some of these in the next section :

Other usages :

Different constructor logic

Of course if we can block the instanciation from the basic class, we can also make a switch or conditional flow according to the type of new.target in order to make multiple behavior of the constructor.

Factory pattern

new.target will be also used to make factory, basically by making a common logic and separate some instanciation based on the value of new.target.

Configure the base class

Of course, you can use this properties to modify the behavior of the base classes that are extended. Like you had an abstract shape class, and you can make all circle blue, and all rectangles green, by managing this in the base class. So the configuration could be easily accessible.

There probably some more usages, and when I will use some of them I will make another articles because it's really a new discovery for me.

Hope you have learned something even if it's not awesome and mindblowing.