DevPath · Learn to code ESPTEN

Object-oriented programming

Static members and private methods

Static members: they belong to the CLASS, not the instance

With static you define properties and methods that live on the class itself, not on each created object. They are accessed by the class name, without new.

Analogy: the instance is each manufactured car; the static part is information about the factory (how many cars it has built, the conversion constant they all use, etc.).

class Circle {
  static PI = 3.14159;           // static property (shared constant)
  constructor(radius) {
    this.radius = radius;
  }
  area() {
    return Circle.PI * this.radius * this.radius;
  }
}
console.log(Circle.PI);          // 3.14159  (on the class, not the instance)

Typical uses

"Factory" methods that create instances more expressively than new:

class User {
  constructor(name) {
    this.name = name;
  }
  static create(name) {          // static factory method
    return new User(name);
  }
}
const u = User.create("Ana");   // reads better than new User("Ana")

Instance counters (a value that belongs to the whole class, not one object):

class Connection {
  static open = 0;
  constructor() {
    Connection.open++;          // increments on every new
  }
}
new Connection();
new Connection();
console.log(Connection.open);   // 2

Utilities that do not need an instance (like Math.max or Array.from): you group related functions inside a class.

Private methods and fields

You already saw private fields #field. You can also have private methods #method(): internal helpers the class uses but that the outside world should not call. They are invisible from outside.

class Password {
  #value;
  constructor(text) {
    this.#value = text;
  }
  // private method: only callable from inside the class
  #isLong() {
    return this.#value.length >= 8;
  }
  isSecure() {
    return this.#isLong();       // the public method delegates to the private one
  }
}
const p = new Password("supersecret");
console.log(p.isSecure());        // true
// p.#isLong()  ->  SyntaxError: the private method does not exist outside

This lets you expose a small, clear public interface, hiding the internal details. Tomorrow you can rewrite #isLong without anyone outside noticing, because nobody could depend on it.

Examples

Static property shared by all instances

class Product {
  static vat = 0.21;
  constructor(price) {
    this.price = price;
  }
  finalPrice() {
    return this.price * (1 + Product.vat);
  }
}
console.log("VAT:", Product.vat);
console.log("Final:", new Product(100).finalPrice());

Instance counter with a static field

class Session {
  static total = 0;
  constructor(user) {
    this.user = user;
    Session.total++;
  }
}
new Session("ana");
new Session("luis");
console.log("Sessions created:", Session.total);

Private method as an internal helper

class Cart {
  #items = [];
  add(price) {
    this.#items.push(price);
  }
  #sum() {
    return this.#items.reduce((a, b) => a + b, 0);
  }
  total() {
    return "Total: " + this.#sum();
  }
}
const c = new Cart();
c.add(10);
c.add(25);
console.log(c.total());
Put this into practice

DevPath is a hands-on course: you read the theory here; in the app you put it into practice with exercises that really run, offline.

Start free in the app →
← Dynamic this: bind, call and applyView the module →