Fragmented Thought

JavaScript class static constants extension on instances

By

Published

Lance Gliser

Heads up! This content is more than six months old. Take some time to verify everything still works as expected.

Ran into an interesting question from a coworker. We were working through surprising (to me) PHP behavior on the usage of self:: vs static::. It's a question of late binding and the accessor. For a PHP reference to get a class's extended constant value from the subclass, you had to use static::.

Then they asked me how it works in JavaScript as we're moving toward React (woo). Had to admit, I had no idea. While I do use JS classes, it's more composition than inheritance if possible. Still, it's useful to know. There's an example below, but the take away is this:

Static constants are somewhat second class, and shouldn’t be used for extension based overrides. Preference functions in javascript.

class ClassA {
    public static MY_VALUE = 'asdf';

    // Possible, but one hell of an awkward turtle.
    // getOutput(){
    //     // @ts-ignore // Required to allow for __proto__ access
    //     return this.__proto__.constructor.MY_VALUE;
    // }

    getOutput(){
        return ClassA.MY_VALUE;
    }
}

class ClassB extends ClassA {
    // Note that WebStorm doesn't even find this be an extended / overridden property
    public static MY_VALUE = 'fdsa';

    // This shows extension.
    getOutput(){
        return ClassB.MY_VALUE;
    }
}

const a = new ClassA();
const b = new ClassB();

describe('constants usage', () => {
    it('a instance of ClassA', () => {
        expect(a).toBeInstanceOf(ClassA)
    });

    it('b instance of ClassB', () => {
        expect(b).toBeInstanceOf(ClassB)
    });

    it('a should return ClassA value of MY_Value', () => {
        expect(a.getOutput()).toBe(ClassA.MY_VALUE)
    });

    it('b should return ClassB value of MY_Value', () => {
        expect(b.getOutput()).toBe(ClassB.MY_VALUE)
    });

});