Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A static field is a property bound directly to a class constructor object rather than to the individual instances created from that class. Because they are attached to the class object itself, static fields are evaluated only once when the class is defined, and their values are shared across the entire execution context.

Syntax and Declaration

Static fields are declared using the static keyword. They can be defined as either public or private (using the # prefix).
class Entity {
  static publicStaticField = 'accessible everywhere';
  static #privateStaticField = 'accessible only within the class';
}

Access Mechanics and Instances

Static fields cannot be accessed through instances of the class. However, the behavior differs depending on whether the field is public or private:
  • Public Static Fields: Attempting to access a public static field on an instantiated object returns undefined because the property does not exist on the instance or its prototype chain.
  • Private Static Fields: Attempting to access a private static field on an instance (e.g., via this.#field inside an instance method) throws a TypeError. The JavaScript engine performs a receiver brand check, and the instance lacks the class constructor’s private brand.
class ServerConfig {
  static publicPort = 8080;
  static #privatePort = 9090;

  getInstancePort() {
    // 'this' refers to the instance, which lacks the static private brand
    return this.#privatePort; 
  }
}

const config = new ServerConfig();

// Public field access on instance
console.log(config.publicPort); // undefined

// Private field access on instance
// config.getInstancePort(); // TypeError: Cannot read private member #privatePort from an object whose class did not declare it

The this Context and Dynamic Binding

Inside static methods, the this keyword is dynamically bound based on how the method is invoked. When a static method is called directly on the class (e.g., Metrics.logConnection()), this refers to the class constructor. However, if a static method is detached from the class (e.g., passed as a callback or destructured), this loses its context. Because ES6 classes execute in strict mode, this becomes undefined. Attempting to access a static field via this in a detached method will result in a runtime TypeError.
class Metrics {
  static activeConnections = 0;

  static logConnection() {
    this.activeConnections++;
    console.log(this.activeConnections);
  }
}

// Invoked on the class: 'this' is Metrics
Metrics.logConnection(); // 1

// Detached invocation
const { logConnection } = Metrics;
// logConnection(); // TypeError: Cannot read properties of undefined (reading 'activeConnections')
To guarantee safe access regardless of invocation context, reference the class constructor directly (e.g., Metrics.activeConnections).

Inheritance and Private Brand Checking

Public static fields participate in the prototype chain. When a subclass extends a base class, it inherits the public static fields of the base class. If a subclass reassigns an inherited public static field, it creates a new static property on the subclass constructor, shadowing the base class property. Private static fields, however, are strictly scoped to the class body where they are defined and require a strict receiver brand check. This creates a critical caveat when combining private static fields with inheritance. If an inherited static method accesses a private static field using this.#field, calling that method on a subclass will throw a TypeError. In this scenario, the subclass is the receiver (this), but it does not possess the base class’s private brand.
class Base {
  static #secret = 'base_secret';

  static getSecretUsingThis() {
    return this.#secret;
  }

  static getSecretSafely() {
    return Base.#secret;
  }
}

class Derived extends Base {}

// Works: The receiver is Base, which has the #secret brand
console.log(Base.getSecretUsingThis()); // 'base_secret'

// Fails: The receiver is Derived, which lacks the Base #secret brand
// console.log(Derived.getSecretUsingThis()); // TypeError: Cannot read private member #secret from an object whose class did not declare it

// Works: Bypasses dynamic 'this' by explicitly referencing the Base class
console.log(Derived.getSecretSafely()); // 'base_secret'
To prevent runtime errors in static methods that may be inherited, developers must access private static fields by explicitly referencing the defining class name (e.g., ClassName.#field) rather than relying on this.
Master JavaScript with Deep Grasping Methodology!Learn More