JavaScript Static Methods & Properties
Methods and properties that belong to the class itself, not to instances.
Basic Static Methods
class MathUtils {
static add(a, b) { return a + b; }
static subtract(a, b) { return a - b; }
static multiply(a, b) { return a * b; }
}
console.log(MathUtils.add(5, 3)); // 8
console.log(MathUtils.multiply(4, 6)); // 24
Remember: Static methods are called on the class: MathUtils.add(), not new MathUtils().add().
Static Properties
Shared across all instances:
class Counter {
static count = 0;
constructor() { Counter.count++; }
static getCount() { return Counter.count; }
}
new Counter(); new Counter(); new Counter();
console.log(Counter.getCount()); // 3
Factory Methods
Named alternatives to constructors — more readable:
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", "[email protected]", "guest"); }
static fromJSON(json) {
let d = JSON.parse(json);
return new User(d.name, d.email, d.role);
}
}
let admin = User.createAdmin("John", "[email protected]");
User.createAdmin() is clearer than new User("John", "[email protected]", "admin").
Complete Example: Singleton
class Database {
static #instance = null;
constructor() {
if (Database.#instance) return Database.#instance;
this.connected = false;
Database.#instance = this;
}
static getInstance() {
if (!Database.#instance) Database.#instance = new Database();
return Database.#instance;
}
connect() { this.connected = true; return this; }
}
let db1 = Database.getInstance();
let db2 = Database.getInstance();
console.log(db1 === db2); // true
Complete Example: Builder Pattern
class QueryBuilder {
#table = ""; #conditions = []; #orderBy = null; #limit = null;
static from(table) { let b = new QueryBuilder(); b.#table = table; return b; }
where(c) { this.#conditions.push(c); return this; }
order(col, dir = "ASC") { this.#orderBy = `${col} ${dir}`; return this; }
limit(n) { this.#limit = n; return this; }
build() {
let q = `SELECT * FROM ${this.#table}`;
if (this.#conditions.length) q += ` WHERE ${this.#conditions.join(" AND ")}`;
if (this.#orderBy) q += ` ORDER BY ${this.#orderBy}`;
if (this.#limit) q += ` LIMIT ${this.#limit}`;
return q;
}
}
let query = QueryBuilder.from("users").where("age > 18").order("name").limit(10).build();
Best Practices
- Use for utility functions — Don’t need instance state
- Use for factory methods — Alternative constructors
- Use static properties — Class-level constants
- Don’t overuse static — Instance methods are more flexible
Common Mistakes
- Calling static on an instance — Use
ClassName.method() thisin static methods — Refers to the class, not an instance- Forgetting
statickeyword — Method becomes an instance method - Overusing static — Prefer instance methods for most logic