JavaScriptStatic Methods & Properties

Static Members

static declares a method or property that belongs to the class itself, not to its instances. You call it through the class — MyClass.help() — and it has no access to a specific instance's data. Static members shine as factories, validators, constants, and bundle-of-utilities homes that still feel related to a class.

Static methods

JS
class Temperature {
  constructor(celsius) { this.celsius = celsius; }

  // Instance method
  toFahrenheit() { return this.celsius * 9 / 5 + 32; }

  // Static method — utility, no instance needed
  static fromFahrenheit(f) {
    return new Temperature((f - 32) * 5 / 9);
  }
}

const t = Temperature.fromFahrenheit(212);
console.log(t.toFahrenheit());   // 212

A common pattern: pair the constructor with one or more static factories named after the input format (fromJSON, fromFahrenheit, ofSeconds).

Static properties

A static field declaration attaches a property to the class. Use it for shared constants, default values, or registries.

JS
class HttpClient {
  static DEFAULT_TIMEOUT = 5000;
  static USER_AGENT = "letcodes/1.0";

  constructor({ timeout = HttpClient.DEFAULT_TIMEOUT } = {}) {
    this.timeout = timeout;
  }
}

console.log(HttpClient.DEFAULT_TIMEOUT);   // 5000
console.log(new HttpClient().timeout);     // 5000
Calling static from instance code

Inside an instance method, the class is accessible via this.constructor (the class that built this object). That works even after subclassing.

JS
class Shape {
  static describe() { return "a shape"; }

  describe() {
    // Refer to the actual class via this.constructor
    return `I am ${this.constructor.describe()}`;
  }
}

class Circle extends Shape {
  static describe() { return "a circle"; }
}

console.log(new Shape().describe());   // 'I am a shape'
console.log(new Circle().describe());  // 'I am a circle' — uses Circle's static
this inside a static method

Inside a static method, this is the class itself. That sounds odd, but it is what makes inherited static methods work correctly with subclasses.

JS
class Model {
  static create(data) {
    return new this(data);   // `this` is the actual class — subclass-friendly
  }
}

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

const u = User.create({ name: "Ada" });
console.log(u instanceof User);    // true — not just Model
Watch out when destructuring statics
`const create = User.create` then calling `create({})` detaches the static method, and `this` becomes `undefined`. Static methods that rely on `this` must be called through their class.
Static initialiser blocks

Modern JavaScript lets you put a static { ... } block in a class. It runs once when the class is evaluated and can populate static state with arbitrary logic.

JS
class Registry {
  static items = new Map();

  static {
    Registry.items.set("default", { id: 0 });
    Registry.items.set("admin",   { id: 1 });
  }

  static get(name) { return Registry.items.get(name); }
}

console.log(Registry.get("admin"));   // { id: 1 }
Static inheritance

When a class extends another, its statics inherit too. Subclass.help walks the prototype chain of the class object itself, just as instances walk theirs.

JS
class Animal {
  static kingdom = "Animalia";
  static info() { return "A living organism"; }
}

class Cat extends Animal {}

console.log(Cat.kingdom);   // 'Animalia'
console.log(Cat.info());    // 'A living organism'

// Inheriting class can override
class Plant extends Animal {
  static kingdom = "Plantae";
}
console.log(Plant.kingdom); // 'Plantae'
When to use static — and when not
  • Use static for factories that produce instances from various input formats.

  • Use static for type guards: Animal.isAnimal(x).

  • Use static for constants related to the class — values that never change per instance.

  • Do not use static to dodge this. If your method ignores instance data, it might belong as a plain top-level function instead.

  • Do not use static to store mutable global state by accident — every test sees the same data.

Static methods inside a base class

JS
class Validator {
  static isEmail(s) {
    return typeof s === "string" && /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(s);
  }

  static isPhone(s) {
    return typeof s === "string" && /^[0-9 +()-]{6,}$/.test(s);
  }
}

console.log(Validator.isEmail("ada@example.com"));   // true
console.log(Validator.isPhone("abc"));               // false

This pattern — a class as a namespace for related helpers — is so common that it sometimes replaces a module of free functions in larger codebases.

Statics on classes vs modules
A class full of static helpers and a module exporting free functions overlap a lot. Pick statics when the helpers feel naturally tied to the class (factories, guards, defaults). Pick free functions when they are reusable across many types.
One sentence
Static members hang off the class itself, not its instances — perfect for factories, validators, and constants that conceptually belong to the type.