READMEJavaScript

README

Module 11 Classes / .3 Static Members

Concept Lesson
Advanced
4 min

Learning Objective

Understand Module 11 Classes well enough to explain it, recognize it in JavaScript, and apply it in a small task.

Why It Matters

This concept is part of the foundation that later lessons and projects assume you already understand.

ClassesStatic MethodsStatic PropertiesStatic Vs Instance ComparisonStatic Initialization Blocks
Private notes
0/8000

Notes stay private to your browser until account sync is configured.

README
1 min read14 headings

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

Skill Check

Test this lesson

Answer 4 quick questions to lock in the lesson and feed your adaptive practice queue.

--
Score
0/4
Answered
Not attempted
Status
1

Which module does this lesson belong to?

2

Which section is covered in this lesson content?

3

Which term is most central to this lesson?

4

What is the best way to use this lesson for real learning?

Your answers save locally first, then sync when account storage is available.
Practice queue