The idea
What it is
Some data belongs to each object, and some data belongs to the class as a whole. An instance member gets a fresh copy for every object you create — your name, your salary. A static member exists exactly once, on the class itself, and every object shares that single copy.
Picture a company. Each employee has their own name badge and own salary — change yours and mine is untouched. But there's one company name printed on the wall that everyone shares. Rename the company and it changes for all of you at once, because there was only ever one of it. Instance = your own badge; static = the sign on the wall.
The one sentence to remember
Instance members live on the object (one per object); static members live on the class (one for everyone). You reach an instance member through an object (alice.salary), and a static member through the class (Employee.company).
Mechanics
How it works
Instance members: one copy per object
An instance field is declared on the class but allocated per object — every new Employee(...) gets its own slot for name and salary. Inside a method, you reach the current object's own copy through this: this.salary. Calling alice.giveRaise() touches only Alice's salary; Bob's is completely separate. That independence is the whole point of objects.
class Employee {
name: string;
salary: number; // instance field — one per object
constructor(name: string, salary: number) {
this.name = name;
this.salary = salary; // each object gets its OWN salary
}
giveRaise(amount: number) {
this.salary += amount; // 'this' = the specific object
}
}
const alice = new Employee("Alice", 100);
const bob = new Employee("Bob", 90);
alice.giveRaise(10); // alice.salary → 110, bob.salary still 90Static members: one copy, shared by all
A static member belongs to the class, not to any object. There is exactly one copy no matter how many objects exist — or even if zero exist. You don't need this, because there's no particular object involved; you call it on the class name itself, like Employee.company or Employee.headcount(). Change it once and every object that reads it sees the new value, because they're all reading the same single box.
- Static field — shared data: a company name, a configuration constant, a running counter of how many objects exist.
- Static method — behavior that doesn't need a specific object: a factory like
Employee.fromCsv(...), or a helper likeMath.max(...). - No
this— a static method can't readthis.salary, because which object's salary would it mean? There isn't one.
class Employee {
static company = "Acme"; // ONE shared box for every employee
static count = 0; // a static counter
name: string;
constructor(name: string) {
this.name = name;
Employee.count++; // bump the shared counter on each hire
}
static headcount() { // static method — no 'this'
return Employee.count;
}
}
const a = new Employee("Alice");
const b = new Employee("Bob");
Employee.company = "Globex"; // change ONCE → every employee sees "Globex"
Employee.headcount(); // 2 — read off the class, not an objectWhen static makes sense
Static shines when the data or behavior truly belongs to the concept, not to any one object: a counter of live instances, a factory method that builds objects, a constant like Math.PI, or a stateless utility function. The test: ask "would this value differ from object to object?" If no — it's static.
The classic gotcha: static is shared mutable state
A mutable static field is effectively a global variable wearing a class's clothes. Because everyone shares the one copy, a change anywhere is visible everywhere — which makes behavior depend on hidden, order-sensitive state that's hard to test and unsafe across threads. Use static state sparingly, and prefer it for constants and counters, not for things that change in surprising ways.
Interactive prototype
See it. Build it. Break it.
A sandboxed, hands-on simulation — no setup, no install. Play with it as you read.
About this simulation
The Employee class card holds one shared box — Employee.company — that belongs to the class. Press Hire employee to stamp instance cards, each with its own name and salary. Give one employee a raise and only that card changes; rebrand the company and every card updates at once. One shared box vs many own boxes.
Hands-on
Try these yourself
Open the prototype above, predict what happens, then verify.
Give a raise — only one box changes
Two employees are seeded on load. Click give raise on just one card and watch only that employee's salary climb while the other stays put. The console narrates instance: alice.salary 100→110 (only alice). Each object owns its own salary.
Rebrand the company — every box changes
Type a new name into the class-level Rebrand company field and press the button. Notice that Employee.company updates and every employee card instantly shows the new company. The console logs static: Employee.company → 'Globex' (all employees updated). There's only one shared copy.
Watch the static counter
Press Hire employee and keep an eye on Employee.headcount in the class card — it ticks up on every hire because the counter lives on the class, not on any one object. Compare it to salary, which is per-employee. Counter = static; salary = instance.
In practice
When to use it — and what trips people up
Reach for a static member when…
- The value is the same for every object and belongs to the concept, not an instance — a company name, an app-wide config, a constant like
Math.PI. - You're counting instances or holding a shared registry —
Employee.headcount, a cache, a connection pool. - You need a factory method that builds objects before any object exists —
User.fromJson(...),Logger.getInstance(). - The function is a pure utility with no per-object state —
Math.max(a, b),StringUtils.capitalize(s).
Default to instance; promote to static deliberately
If a value could ever differ between two objects, it's instance data — keep it on the object. Reach for mutable static state only when the sharing is genuinely intended, because once it's static, every object is coupled to that single copy.
What it gives you
- One source of truth for data that's truly shared — change it once, everyone sees it.
- No memory wasted on a duplicate copy in every object; constants and config live in a single place.
- Factory methods and utilities are reachable without first creating an object.
- Static counters and registries give the class a clean, central place to track all its instances.
Common mistakes
- Mutable static state is hidden global state — any code can change it and every object is affected.
- Hard to test and mock: tests share the one static value, so state leaks between them and order starts to matter.
- Not thread-safe by default — concurrent writes to a shared static field can corrupt it without explicit synchronization.
- Encourages tight coupling: callers depend on a global class rather than on an object they were handed.
Reference
Code & further reading
A minimal reference implementation and pointers worth bookmarking.
// static = shared by the class · instance = per object. Pick a language above.
class Employee {
static company = "Acme"; // ONE shared copy for every employee
static headcount = 0; // a static counter
// instance fields — one copy PER object
constructor(public name: string, public salary: number) {
Employee.headcount++; // bump the shared counter on each hire
}
giveRaise(amount: number) {
this.salary += amount; // 'this' → only THIS employee's salary
}
// static method — no 'this'; called on the class
static rebrand(name: string) {
Employee.company = name; // changes the shared copy for everyone
}
}
const alice = new Employee("Alice", 100);
const bob = new Employee("Bob", 90);
alice.giveRaise(10); // alice.salary → 110, bob still 90 (own box)
Employee.rebrand("Globex"); // every employee now reports "Globex" (shared)
Employee.headcount; // 2 — read off the class itselfReferences & further reading
5 sources- Docsdocs.oracle.com
Oracle — Understanding Class Members
The canonical Java tutorial on static (class) vs instance fields and methods, with clear before/after examples.
- Docsdeveloper.mozilla.org
MDN — static (JavaScript)
Reference for static fields and methods in JavaScript classes — called on the class, not on instances.
- Docsdocs.python.org
Python docs — classmethod
How
@classmethod(and@staticmethod) define behavior on the class itself rather than on instances. - Articleen.wikipedia.org
Wikipedia — Class variable
A language-agnostic overview of class (static) variables versus instance variables and why the distinction matters.
- Articlerefactoring.guru
Refactoring.Guru — Singleton
A common (and often criticized) use of static state — useful to see both its appeal and its global-state pitfalls.
Knowledge check
Did it land?
Quick questions, answers revealed on submit. Nothing is scored or saved.
question 01 / 04
You create alice and bob from Employee, then call alice.giveRaise(10). What happens to bob.salary?
question 02 / 04
Employee.company is a static field set to "Acme". You change it to "Globex". What do existing employee objects report as their company?
question 03 / 04
Why can't a static method use this?
question 04 / 04
Which is the biggest risk of using a mutable static field?
0/4 answered