Search code examples
javascriptclassoopecmascript-6redundancy

Better method for acting upon state change in JavaScript classes


I'm trying to move from procedural to object-oriented JavaScript and I'm coming up against an issue I'm sure there's an answer to, but I can't work it out.

Currently, each of my methods checks the state of a property, and then performs an action based on that state. What I'd rather do is update the state and those methods execute as a result of the state change. Is that possible, or am I missing the point?

Here's what I have currently:

class ClassExample {
    constructor({state = false} = {}) {
        this.state = state;
        ...
    }

    aMethod() {
        if(this.state) {
            //Do something
            this.state = false;
        } else {
            //Do something else
            this.state = true;
        }
    }

    bMethod() {
        if(this.state) {
            //Do something
            this.state = false;
        } else {
            //Do something else
            this.state = true;
        }
    }
}

And:

const myObject = new ClassExample();
myObject.aMethod();
myObject.bMethod();

Given both methods are checking the same property, it's resulting in a lot of redundant if statements. Is there a better way to organise this class to achieve the same result?


Solution

  • I'd suggest you use an event driven system based on the EventEmitter() object built into node.js.

    To keep track of state changes, you can define a setter for your state variables so that any time someone sets a new state, then your setter function will get called and it can then trigger an event that indicates the state changed. Meanwhile, anyone in your object out outside your object can register an event listener for state changes.

    Here's a short example:

    const EventEmitter = require('events');
    
    class ClassExample extends EventEmitter {
        constructor(state = 0) {
            super();
            // declare private state variable
            let internalState = state;
            // define setter and getter for private state variable
            Object.defineProperty(this, "state", {
                get: function() {
                    return internalState;
                },
                set: function(val) {
                    if (internalState !== val) {
                        internalState = val;
                        // send out notification 
                        this.emit("stateChanged", val);
                    }
                }
            });
        }
    }
    
    let e = new ClassExample(1);
    console.log(e.state);
    
    e.on("stateChanged", function(newVal) {
        console.log("state has changed to ", newVal);
    });
    
    e.state = 3;
    console.log(e.state);