Docs
README
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 helpers | Store instance-specific data |
| Factory methods | Complex mutable state |
| Configuration/constants | Rely heavily on static mutation |
| Caching shared resources | Create tight coupling |
| Counters and registries | Forget 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
- ā¢Static members belong to the class, not instances
- ā¢Use
statickeyword before property or method - ā¢Access via class name:
ClassName.member - ā¢
thisin static methods refers to the class - ā¢Static blocks enable complex initialization (ES2022)
- ā¢Statics are inherited through the static prototype chain
- ā¢Perfect for: factories, utilities, singletons, registries