JavaScript Static Methods and Private Class Fields

JavaScript ES6 introduced static methods as part of its class syntax, allowing methods to belong to a class rather than its individual instances. Modern JavaScript also supports private class fields, which allow a class to hide internal data from code outside the class.

These features help developers organize code, control access to data, and create reusable class functionality.

For example, a MathHelper class can provide a static method to calculate a square without creating an object. A BankAccount class can use a private field to store a balance that cannot be accessed directly from outside the class.

In this tutorial, you will learn how static methods and private class fields work, when to use them, and how they differ from regular instance methods and public properties.

What Are Static Methods in JavaScript?

A static method is a method that belongs to a class itself rather than to individual instances created from that class.

You define a static method using the static keyword inside a class.

Static methods are useful for utility operations, calculations, and functionality that does not require data stored on a particular instance.

Static Method Syntax

class ClassName {
    static methodName() {
        // Code to execute
    }
}

You can call the method directly through the class name.

Example of a Static Method

class MathHelper {
    static square(number) {
        return number * number;
    }
}

console.log(MathHelper.square(5));
console.log(MathHelper.square(8));

Output:

25
64

In this example:

  • class MathHelper defines the class.
  • static declares a static method.
  • square(number) accepts a number and returns its square.
  • MathHelper.square(5) calls the method directly through the class.

You do not need to create an instance of MathHelper to use its static method.

Calling Static Methods Through a Class

Static methods are called using the class name followed by dot notation.

class Calculator {
    static add(a, b) {
        return a + b;
    }

    static multiply(a, b) {
        return a * b;
    }
}

console.log(Calculator.add(10, 20));
console.log(Calculator.multiply(5, 4));

Output:

30
20

Both methods belong to the Calculator class. They can be called directly without creating an object.

This is useful when an operation does not depend on the properties of a specific instance.

Static Methods Cannot Normally Be Called Through Instances

A static method is not available as an ordinary instance method.

class MathHelper {
    static square(number) {
        return number * number;
    }
}

const helper = new MathHelper();

console.log(MathHelper.square(4));
// Output: 16

// helper.square(4); // TypeError

The correct way to call the method is MathHelper.square(4).

Creating an instance does not automatically make the class’s static methods available on that instance.

Static Methods vs Instance Methods

JavaScript classes can contain both static methods and instance methods.

FeatureStatic MethodInstance Method
Belongs toThe classThe class prototype for ordinary class methods
Called throughClass nameInstance
Requires an instanceNoUsually yes
Typical purposeUtility operationsBehavior related to an object
ExampleCalculator.add(2, 3)calculator.add(2, 3)

Example of Both Methods

class User {
    constructor(name) {
        this.name = name;
    }

    greet() {
        return `Hello, ${this.name}!`;
    }

    static describe() {
        return "A User represents a person.";
    }
}

const user = new User("Rahul");

console.log(user.greet());
console.log(User.describe());

Output:

Hello, Rahul!
A User represents a person.

The greet() method uses the instance’s name. The describe() method provides general information about the class and can be called without creating an instance.

Using Static Methods with Other Static Methods

One static method can call another static method using this or the class name.

class Calculator {
    static square(number) {
        return number * number;
    }

    static sumOfSquares(a, b) {
        return this.square(a) + this.square(b);
    }
}

console.log(Calculator.sumOfSquares(3, 4));

Output:

25

The method calculates (3^2 + 4^2), which equals 25.

Here, this.square() works because the method is called through Calculator. In more complex inheritance scenarios, the value of this can vary depending on how the static method is invoked.

What Are Private Class Fields in JavaScript?

Private class fields are properties that can be accessed only from within the class body where they are declared. They use the hash symbol (#) before the field name.

Private fields allow a class to keep internal data hidden from outside code.

For example, a bank account might store its balance in a private field so that outside code cannot directly change it.

Private Field Syntax

class ClassName {
    #privateField;

    constructor(value) {
        this.#privateField = value;
    }
}

The #privateField declaration creates a private field. It must be declared in the class body before it can be used as a private field.

Unlike a property named _privateField, a field beginning with # is enforced by JavaScript’s language rules.

Example of a Private Class Field

class User {
    #password;

    constructor(password) {
        this.#password = password;
    }

    checkPassword(password) {
        return this.#password === password;
    }
}

const user = new User("abc123");

console.log(user.checkPassword("abc123"));
console.log(user.checkPassword("wrong"));

Output:

true
false

In this example:

  • #password is a private field.
  • The constructor initializes the field.
  • checkPassword() accesses the field from inside the class.
  • Code outside the class cannot read user.#password directly.

This example demonstrates private field syntax only. Real applications should not store passwords as plain text; they should use appropriate password hashing and authentication practices.

Accessing Private Fields Inside a Class

Private fields can be read and modified by methods defined within the class that declares them.

class BankAccount {
    #balance;

    constructor(balance) {
        this.#balance = balance;
    }

    getBalance() {
        return this.#balance;
    }

    deposit(amount) {
        if (amount > 0) {
            this.#balance += amount;
        }
    }
}

const account = new BankAccount(1000);

account.deposit(500);

console.log(account.getBalance());

Output:

1500

The #balance field stores the account balance privately. The deposit() method updates it, while getBalance() returns the current value.

This design allows the class to control how the balance is changed.

Private Fields Cannot Be Accessed Outside the Class

JavaScript prevents code outside the declaring class from directly accessing its private fields.

class Employee {
    #salary;

    constructor(salary) {
        this.#salary = salary;
    }

    getSalary() {
        return this.#salary;
    }
}

const employee = new Employee(40000);

console.log(employee.getSalary());

// console.log(employee.#salary); // SyntaxError

Output:

40000

The getSalary() method works because it accesses #salary from inside the class.

The commented expression would cause a syntax error if uncommented because private fields cannot be referenced directly outside their declaring class.

Private fields provide stronger access restrictions than a naming convention such as _salary.

Private Fields vs Public Properties

Public properties can be accessed directly from outside an object. Private fields cannot.

class Product {
    name;
    #cost;

    constructor(name, cost) {
        this.name = name;
        this.#cost = cost;
    }

    getCost() {
        return this.#cost;
    }
}

const product = new Product("Laptop", 40000);

console.log(product.name);
console.log(product.getCost());

Output:

Laptop
40000

The name field is public, so you can access it through product.name. The #cost field is private, so you must use a class method to retrieve its value.

FeaturePublic PropertyPrivate Field
Namingname#name
Access from outsideAllowedNot allowed directly
DeclarationOptional in many casesMust be declared in the class body
Main purposeExpose object dataKeep internal data restricted

Private fields are useful when a class must enforce rules about how its internal data is accessed or changed.

Combining Static Methods and Private Fields

Static methods can also access private static fields declared by the same class. Private static fields belong to the class itself rather than individual instances.

class AppConfig {
    static #appName = "Web4Learners";

    static getAppName() {
        return this.#appName;
    }
}

console.log(AppConfig.getAppName());

Output:

Web4Learners

Here, #appName is a private static field. The getAppName() static method can access it because both belong to the same class.

Outside code cannot directly read AppConfig.#appName.

Private Instance Fields and Static Methods Are Different

A static method does not automatically have access to a particular instance’s private fields through this, because this normally refers to the class when the method is called through the class.

For example, a static method can receive an instance as an argument and access its private fields if the method is defined inside the class that declares those fields.

class Account {
    #balance;

    constructor(balance) {
        this.#balance = balance;
    }

    static getBalance(account) {
        return account.#balance;
    }
}

const account = new Account(2500);

console.log(Account.getBalance(account));

Output:

2500

This works because getBalance() is defined inside Account, the class that declares #balance. Private field access is based on the class’s private-name access rules, not simply on whether a method is static or an instance method.

Common Mistakes to Avoid

Forgetting the Hash Symbol

Private fields must use the # symbol in their declaration and when accessing them.

class User {
    #name = "Rahul";

    getName() {
        return this.#name;
    }
}

Writing this.name instead of this.#name refers to a different property.

Trying to Access Private Fields Outside the Class

This is not allowed:

class User {
    #name = "Rahul";
}

// user.#name; // SyntaxError

Use a public method or getter if outside code needs controlled access to the value.

Calling a Static Method Through an Instance

Static methods belong to the class, so call them through the class name.

class Helper {
    static greet() {
        return "Hello!";
    }
}

console.log(Helper.greet());

Output:

Hello!

Assuming an Underscore Makes a Field Private

A property such as _balance is still accessible from outside the class. The underscore is only a naming convention.

A declaration such as #balance creates a genuine private field enforced by JavaScript.

Frequently Asked Questions

What is a static method in JavaScript?

A static method belongs to a class rather than its individual instances. It is defined using static and normally called through the class name.

What are private class fields?

Private class fields are properties declared with the # prefix. They can be accessed only from within the class that declares them, subject to JavaScript’s private-field rules.

Can static methods access private fields?

Yes. A static method can access private static fields and can also access private instance fields on appropriate instances when those fields belong to the same class.

Can an object access a static method?

Not as an ordinary instance method. Static methods are normally called through the class itself, although they can be accessed through the class’s inheritance chain or other explicit references.

Are private fields the same as underscore properties?

No. An underscore is just a naming convention. The # prefix creates a private field with language-enforced access restrictions.

When should I use static methods?

Use static methods for functionality that belongs to the class as a whole, such as utility calculations, factory methods, or operations that do not require a particular instance.

Conclusion

Static methods and private class fields help you design JavaScript classes with clearer responsibilities and better control over internal data.

Static methods provide functionality through the class itself, while private fields restrict direct access to internal properties. By combining these features appropriately, you can build reusable classes that expose only the functionality other parts of your application need.