DevAcademy
LearnJavaScriptStatic, Private, and Getter/Setter Members
AdvancedJavaScript

Static, Private, and Getter/Setter Members

Go beyond basic classes with static methods and properties, true private fields using #, and getter/setter methods that let you control how a property is read and written.

Reading Time

18 min

Lesson

Lesson 41 of 48

Beyond the Basics

A basic class with a constructor and instance methods covers most everyday needs, but JavaScript classes support a few more advanced members that solve specific, common problems: static members for behavior that belongs to the class itself rather than any one instance, private fields for genuine encapsulation, and getters/setters for controlling how a property is read or written. Each of these earns its place by making certain patterns much cleaner to express.

Static Methods and Properties

A member marked with the static keyword belongs to the class itself, not to any individual instance — you call it as ClassName.member() rather than instance.member(). Static members are useful for utility functions related to the class's purpose (like a factory that builds instances in a special way) or for shared data that all instances should be aware of, but that doesn't belong to any single one of them.

A Static Method and a Static Property

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Static Members Are Not Inherited to Instances

Static properties and methods live only on the class itself. Trying to access them through an instance, like alice.totalUsers, will not work — you must always go through the class name, or through this inside another static method.

Private Fields and Methods with #

Before the # syntax, JavaScript had no true way to make a class member private — properties assigned with this were always accessible from outside the class, just by convention or a leading underscore that anyone could ignore. Prefixing a field or method name with # makes it genuinely private: it can only be accessed from inside the class body, and even attempting to read it from outside throws a SyntaxError rather than quietly returning undefined.

A Truly Private Field

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Private Fields Must Be Declared in the Class Body

Unlike regular instance properties, you can't create a private field on the fly by just assigning this.#something inside a method — every private field must first be declared directly in the class body (even if only as #balance; with no initial value), or JavaScript throws a SyntaxError.

Getters and Setters

The get and set keywords let you define a property that looks like a plain field from the outside, but is actually backed by a method. A getter runs custom code whenever the property is read; a setter runs custom code whenever it's assigned. This is how you validate incoming values, compute a derived value on the fly, or expose a controlled view onto a private field, all while keeping the calling code as simple as account.balance rather than account.getBalance().

Getters and Setters on Their Own

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Combining Them: a Private Field Behind a Getter/Setter

The most practical pattern combines all three features: a private field holds the real data, and a public getter/setter pair controls how that data is read and written — including validation. Outside code interacts with a clean property name and never touches the private field directly, but every read and write can be checked or transformed.

A Validated Property Backed by a Private Field

Try it yourself — edit and run

Console Output

Click “Run” to see the console output here.

Class Feature Cheat Sheet

FeatureSyntaxCalled OnPurpose
Static method/propertystatic name() / static name = valueThe class itselfShared behavior/data not tied to one instance
Private field/method#namethis, inside the class onlyTrue encapsulation — inaccessible from outside
Getterget name()Read like a property: obj.nameCompute or expose a value on read
Setterset name(value)Assign like a property: obj.name = xValidate or transform a value on write

When to Reach for Each Feature

  • Use static members for factory methods or class-wide counters/configuration
  • Use private fields whenever internal state should never be touched from outside the class
  • Use a getter when you want a computed, read-only-feeling property
  • Use a setter alongside a private field when you need to validate incoming values
  • Combine private fields with getters/setters for controlled, safe access to internal data

Private Fields Are Also useful for Preventing Naming Collisions

Because # fields are scoped to the class body, a subclass and a parent class can each safely use a private field with the same name without any conflict — they are completely separate. This is one more advantage private fields have over plain this properties, which live in one shared namespace on the instance.

Getters/Setters Can Hide Expensive Work

Because a getter is called with simple property syntax (obj.value), it's easy to forget that it might be doing real computation behind the scenes, unlike a plain property lookup. Avoid putting slow or side-effect-heavy logic inside a getter — callers reasonably expect reading a property to be fast and safe to do repeatedly.

Interview Questions

Quick Quiz

1. How do you call a static method named createGuest() defined on a class named User?

2. What symbol is used to declare a private field in a class?

3. What happens if you try to access a private field from outside the class that declares it?

4. What is the purpose of a getter in a class?

5. In the Temperature class example, why does temp.celsius = "hot" throw an error?