DEV Community

Joe Pea
Joe Pea

Posted on • Edited on

4 1

JavaScript's new class fields will shoot you in the foot!

TLDR, paste the following in your Chrome console:

class Animal {
    #sound = 'rustling noise in the bushes'

    get sound() { return this.#sound }
    set sound(val) { this.#sound = val }

    makeSound() {
        console.log(this.#sound)
    }
}

const a = new Animal
a.makeSound() // 3.14

class Lion extends Animal {
    sound = 'RAWR!'
}

const lion = new Lion
lion.makeSound() // BUG! Expected "RAWR!" but got "rustling noise in the bushes"

The example does not work as you may expect because the expression sound = 'RAWR!' uses [[Define]] semantics instead of [[Set]] semantics.

What are [[Define]] and [[Set]] semantics?

Let me explain using plain ES6 code without class fields.

Using [[Set]] semantics, the Lion class can be written like this:

class Lion extends Animal {
    constructor() {
        super()
        this.sound = 'RAWR!'
    }
}

That version will trigger super class getters/setters in the expression this.sound = 'RAWR!'. The result of lion.makeSound() will be "RAWR!" because that value will be stored inside of the Animal class's private #sound field.

Now, using [[Define]] semantics, we would instead "define" the property on the instance, like so:

class Lion extends Animal {
    constructor() {
        super()
        Object.defineProperty(this, 'sound', { value: 'RAWR!' })
    }
}

This version is what class fields do. Class fields define the property on this directly, so the sound field does not trigger the super class getter/setter that is inside of Animal, therefore the 'RAWR!' value will never be stored inside of Animal's private #sound field. Thus we've been shot in the foot.

Class fields do not keep inheritance as a first-class citizen in the design of JS classes.

This is one of the reasons why many people don't like the class-fields proposal, and it is unfortunate that Chrome's V8 engine is already shipping the feature despite so much push-back from the community.

Here's the design bug reported to Chrome: https://bugs.chromium.org/p/chromium/issues/detail?id=962192

Ever since ES6 features started rolling out, there hasn't been any feature more controversial and disliked than the current class-fields proposal.

If you have any thoughts on (private or public) class-fields, please leave your thoughts over in those GitHub issues. The more community input we get, the better.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Top comments (0)

SurveyJS custom survey software

JavaScript Form Builder UI Component

Generate dynamic JSON-driven forms directly in your JavaScript app (Angular, React, Vue.js, jQuery) with a fully customizable drag-and-drop form builder. Easily integrate with any backend system and retain full ownership over your data, with no user or form submission limits.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay