All Articles

JavaScript: Class Fields

Class Fields

Class fields is a new feature in JavaScript. This proposal started as two proposals: public fields and private fields proposals but it is now combined in one. Right now, it is in Stage 3 of TC39 so we can expect it to be in our everyday code really soon.

Public Fields

Previously classes just had methods but now we can add any properties to our class.

class User {
  name = "John";

  message() {
    console.log(`User is ${this.name}`);
  }
}

const firstUser = new User();
firstUser.message(); // "User is John"
console.log(firstUser.name); // "John"

If we don’t define it differently, every property that is defined in a class is a public property which means we can modify it outside of the class.

class User {
  name = "John";

  message() {
    console.log(`User is ${this.name}`);
  }
}

const firstUser = new User();
firstUser.name = "Ben";
firstUser.message(); // "User is Ben"
console.log(firstUser.name); // "Ben"

Private Fields

To define a private property we use # prefix. Properties defined like this can’t be accessed or modified outside of the class.

class User {
  name = "John";
  #cityCode = 23;
  message() {
    console.log(`User is ${this.name} with city code ${this.#cityCode}`);
  }
}

const firstUser = new User();
firstUser.message(); // "User is John with city code 23"
firstUser.#cityCode = 25 //Error: Private field '#cityCode' must be declared in an enclosing class
console.log(firstUser.#cityCode) //Error: Private field '#cityCode' must be declared in an enclosing class

When it comes to private methods they are planned to be defined in the same way, but they are part of different proposals. That proposal is in Stage 3 too and it builds on the class fields proposal. With these two proposals any class element can be private.

class User {
  name = "John";
  #cityCode = 23;

  #getName() {
    return this.name;
  }
  message() {
    console.log(`User is ${this.#getName()} with city code ${this.#cityCode}`);
  }
}

const firstUser = new User();
firstUser.message(); // "User is John with city code 23"

What does that mean for static properties?

With these changes we not only have private and public properties of class, but private and public static properties. Similar to static methods, static properties aren’t called on instances of the class. Instead, they’re called on the class itself.

class User {
  static name = "John";
  static #cityCode = 23;

  message() {
    console.log(`User is ${User.name} with city code ${User.#cityCode}`);
  }
}

const firstUser = new User();
firstUser.message(); // "User is John with city code 23"
console.log(User.name); // "John"
console.log(User.#cityCode); //Error: Private field '#cityCode' must be declared in an enclosing class

Method behaviour is similar.

class User {
  name = "John";
  #cityCode = 23;

  static #privateDefaultMessage() {
    return "Hi user!";
  }

  static publicDefaultMessage() {
    console.log(User.#privateDefaultMessage());
  }

  message() {
    console.log(`User is ${this.name} with city code ${this.#cityCode}`);
  }
}
User.publicDefaultMessage(); //"Hi user!"

Like we mentioned, all of these proposals are in an experimental phase and also have a lot of critics. Especially, because of the usage of the # prefix instead of the “private” prefix like in most other languages. Right now, all these features can be used within several JavaScript engines so whether we like it, or not they are here to stay.

Like what you've read? Join our newsletter

Launching a new JavaScript project? Need help on an existing project? Work with us