Docs

11.3-Static-Members

8.3 Static Members

Overview

Static members belong to the class itself, not to instances. They're accessed via the class name, not through this.

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│            MyClass                       │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│  Static Members (on class itself):      │
│  ā”œā”€ MyClass.staticProperty              │
│  ā”œā”€ MyClass.staticMethod()              │
│  └─ MyClass.#privateStatic              │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│  Instance Members (on objects):         │
│  ā”œā”€ this.property                       │
│  ā”œā”€ this.method()                       │
│  └─ this.#privateField                  │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Static Methods

class MathUtils {
  static PI = 3.14159;

  static square(x) {
    return x * x;
  }

  static cube(x) {
    return x * x * x;
  }

  static max(...numbers) {
    return Math.max(...numbers);
  }
}

// Access via class name
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.square(5)); // 25
console.log(MathUtils.cube(3)); // 27

// NOT via instances
const utils = new MathUtils();
// utils.square(5);  // TypeError: utils.square is not a function

Static Properties

class Counter {
  static count = 0; // Public static property
  static #instances = []; // Private static property

  constructor(name) {
    this.name = name;
    Counter.count++;
    Counter.#instances.push(this);
  }

  static getInstances() {
    return [...Counter.#instances];
  }

  static resetCount() {
    Counter.count = 0;
    Counter.#instances = [];
  }
}

new Counter('A');
new Counter('B');
console.log(Counter.count); // 2
console.log(Counter.getInstances()); // [Counter, Counter]

Static vs Instance Comparison

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ Aspect             │ Static                │ Instance              │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ Declaration        │ static keyword        │ No keyword            │
│ Access             │ ClassName.member      │ this.member           │
│ Shared?            │ Yes, across all       │ No, per instance      │
│ Uses `this`?       │ No (undefined)        │ Yes                   │
│ Inherited?         │ Yes (static chain)    │ Yes (prototype chain) │
│ Use Case           │ Utilities, factories  │ Object state/behavior │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Static Initialization Blocks

ES2022 introduced static initialization blocks for complex static setup:

class Database {
  static connection;
  static config;

  // Static initialization block
  static {
    console.log('Initializing Database class...');

    // Complex initialization logic
    this.config = {
      host: process.env.DB_HOST || 'localhost',
      port: parseInt(process.env.DB_PORT) || 5432,
      name: process.env.DB_NAME || 'mydb',
    };

    // Can use try/catch
    try {
      this.connection = this.createConnection(this.config);
    } catch (e) {
      console.error('Failed to create connection:', e);
      this.connection = null;
    }
  }

  static createConnection(config) {
    return { config, connected: true };
  }
}

Static this Context

Inside static methods, this refers to the class itself:

class Factory {
  static version = '1.0';

  static create() {
    // 'this' is the class
    console.log(this.version);
    return new this(); // Creates instance of the class
  }
}

// Works with inheritance
class ChildFactory extends Factory {
  static version = '2.0';
}

const instance = ChildFactory.create();
// Logs "2.0" and creates ChildFactory instance

Common Static Patterns

Factory Pattern

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

  static createAdmin(name, email) {
    return new User(name, email, 'admin');
  }

  static createGuest() {
    return new User('Guest', null, 'guest');
  }

  static fromJSON(json) {
    const data = JSON.parse(json);
    return new User(data.name, data.email, data.role);
  }
}

const admin = User.createAdmin('Alice', 'alice@example.com');
const guest = User.createGuest();

Singleton Pattern

class Logger {
  static #instance = null;

  constructor() {
    if (Logger.#instance) {
      return Logger.#instance;
    }
    Logger.#instance = this;
    this.logs = [];
  }

  static getInstance() {
    if (!Logger.#instance) {
      Logger.#instance = new Logger();
    }
    return Logger.#instance;
  }

  log(message) {
    this.logs.push({ message, timestamp: new Date() });
  }
}

Registry Pattern

class ComponentRegistry {
  static #components = new Map();

  static register(name, component) {
    if (this.#components.has(name)) {
      throw new Error(`Component "${name}" already registered`);
    }
    this.#components.set(name, component);
  }

  static get(name) {
    return this.#components.get(name);
  }

  static getAll() {
    return new Map(this.#components);
  }
}

Static Members and Inheritance

Static Chain:
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ Parent              │
│ ā”œā”€ static method()  │
│ └─ static prop      │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
          │ [[Prototype]]
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ Child               │
│ └─ (inherits static)│
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Child.method() → looks up Parent.method
Child.prop → looks up Parent.prop
class Animal {
  static kingdom = 'Animalia';

  static describe() {
    return `Kingdom: ${this.kingdom}`;
  }
}

class Dog extends Animal {
  static kingdom = 'Animalia'; // Can override
  static species = 'Canis familiaris';

  static describe() {
    return `${super.describe()}, Species: ${this.species}`;
  }
}

console.log(Animal.describe()); // "Kingdom: Animalia"
console.log(Dog.describe()); // "Kingdom: Animalia, Species: Canis familiaris"

Best Practices

Do āœ“Don't āœ—
Use for utilities and helpersStore instance-specific data
Factory methodsComplex mutable state
Configuration/constantsRely heavily on static mutation
Caching shared resourcesCreate tight coupling
Counters and registriesForget inheritance implications

Quick Reference

class Example {
  // Static public property
  static publicProp = 'value';

  // Static private property
  static #privateProp = 'secret';

  // Static public method
  static publicMethod() {
    return this.#privateProp; // Can access private
  }

  // Static private method
  static #privateMethod() {
    return 'internal';
  }

  // Static initialization block
  static {
    console.log('Class initialized');
    this.computed = this.publicProp.toUpperCase();
  }

  // Static getter
  static get info() {
    return `${this.publicProp}:${this.computed}`;
  }

  // Static setter
  static set info(value) {
    this.publicProp = value;
    this.computed = value.toUpperCase();
  }
}

Key Takeaways

  1. •Static members belong to the class, not instances
  2. •Use static keyword before property or method
  3. •Access via class name: ClassName.member
  4. •this in static methods refers to the class
  5. •Static blocks enable complex initialization (ES2022)
  6. •Statics are inherited through the static prototype chain
  7. •Perfect for: factories, utilities, singletons, registries
.3 Static Members - JavaScript Tutorial | DeepML