Private, Protected, and Public Class Members in JavaScript

Updated: March 14, 2023 By: Goodman Post a comment

JavaScript classes, which were added in ECMAScript 2015 (ES6), are a way of creating objects with a common structure and behavior. They can have different kinds of members, such as properties (fields) and methods (functions).

By default, class members are public, which means they can be accessed from anywhere. However, you can also create private class members by using a hash # prefix. Private members are only accessible within the class itself and cannot be inherited by subclasses.

JavaScript doesn’t have native support for protected members, which are accessible within the class and its subclasses but not outside. However, you can emulate this behavior by using symbols or weak maps.

Now, it’s time to see some code.

Public Properties and Methods

Public properties and methods of a class are declared without any prefixes. They can be accessed by any code that has a reference to the class instance.

Example:

class Website {
  // public field
  name;

  // public method
  constructor(name) {
    this.name = name;
  }

  // public method
  greet() {
    console.log(`Hello, welcome to ${this.name}.`);
  }
}

let obj = new Website('slingacademy.com');
obj.greet()

Output:

Hello, welcome to slingacademy.com.

Private Members

Private members are declared with a hash # prefix. They can only be accessed within the class body. They are not inherited by subclasses (don’t forget that or you will be very likely to run into a great deal of trouble in the future).

Example:

class Counter {
  // this is a private property
  #count = 0;

  increment() {
    // only methods of this class can access this member
    this.#count++;
  }

  // we need a public method to get the value of the private member
  getCount() {
    return this.#count; 
  }
}

let counter = new Counter();
counter.increment();
counter.increment();
console.log(counter.getCount());
// output: 2

If you try to access the private field #count outside the class like this:

console.log(counter.#count);

You’ll receive this error:

Uncaught SyntaxError: Private field '#count' must be declared in an enclosing class

Protected Members

As mentioned above, protected members are not supported by JavaScript natively.

However, many JavaScript developers use the underscore character _ for protected members as a convention or a naming pattern. It is not enforced by the language itself. The underscore prefix indicates that the member is intended to be used only by the class itself or its subclasses, but not by other code. It is a way of signaling to other developers that they should respect the encapsulation principle and not access or modify those members directly.

It is important to note that the convention does not prevent anyone from accessing or modifying those members if they really want to. It is just a matter of good practice and code readability.

Example:

class Animal {
  constructor(name) {
    // this is a protected member, indicated by the _ prefix
    this._name = name; 
  }

  getName() {
    // we can access the protected member from within the class or subclasses
    return this._name; 
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    // we call the parent constructor with the name argument
    super(name); 

    // this is another protected member
    this._breed = breed; 
  }

  getBreed() {
    // we can access the protected member from within the class or subclasses
    return this._breed; 
  }

  introduce() {
    // we can access both protected members from within the subclass
    console.log(`I am ${this.getName()}, a ${this.getBreed()} dog.`); 
  }
}

let dog = new Dog('Spot', 'Labrador');

dog.introduce(); 
console.log(dog.getName()); 

// this works, but this is not recommended as it violates encapsulation principles
console.log(dog._name); 

// this works, but again this is not recommended for the same reason
console.log(dog._breed); 

Output:

I am Spot, a Labrador dog.
script.js:36 Spot
script.js:39 Spot
script.js:42 Labrador

Conclusion

In general, you will work with public properties and methods the most, then less often than with private members. Cases involving protected members are quite rare and should be used with caution with unambiguous comments.