Classes in JavaScript
JS classes as sugar over prototypes — constructors, extends, super, fields, and what still differs from classical OOP.
- javascript
- classes
- prototype
- oop
class syntax is not a new object model. It is cleaner syntax for constructor functions + prototypes. Under the hood you still have prototypes, [[Prototype]] links, and method sharing on .prototype. That framing keeps you honest in interviews and debugging.
Shape of a class
class User {
constructor(name) {
this.name = name;
this.createdAt = Date.now();
}
greet() {
return `Hi, ${this.name}`;
}
static isUser(x) {
return x instanceof User;
}
}
const u = new User('Ada');
u.greet(); // "Hi, Ada"
User.isUser(u); // true
typeof User; // "function"
u.greet === User.prototype.greet; // true — shared method
Calling User() without new throws. Class bodies are always strict mode.
extends and super
class Animal {
constructor(name) {
this.name = name;
}
speak() {
return `${this.name} makes a noise`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // must call before using this
this.breed = breed;
}
speak() {
return `${super.speak()} — woof`;
}
}
const d = new Dog('Rex', 'mutt');
d.speak(); // "Rex makes a noise — woof"
d instanceof Dog; // true
d instanceof Animal; // true
super.method() resolves on the parent prototype. super() in the constructor invokes the parent constructor.
Fields (public and private)
class Counter {
#value = 0; // private
label = 'count'; // public field (per instance)
inc() {
this.#value += 1;
return this.#value;
}
get value() {
return this.#value;
}
}
const c = new Counter();
c.inc(); // 1
// c.#value // SyntaxError outside class
Public fields land on the instance; methods stay on the prototype (unless you use arrow class fields, which create per-instance functions).
class Widget {
// per-instance; lexical this — useful for handlers
onClick = () => {
console.log(this);
};
// shared on prototype
render() {}
}
What classes do not give you
- Multiple inheritance
- True method overloading
- Private members that erase at runtime for “security” (they’re language-enforced, not encryption)
- Automatic binding of methods when detached:
const { inc } = new Counter();
// inc() // loses this if it used this without an arrow field
Prototype equivalence (mental model)
// roughly equivalent idea
function User(name) {
this.name = name;
}
User.prototype.greet = function () {
return `Hi, ${this.name}`;
};
extends sets up Subclass.prototype → Parent.prototype and Subclass → Parent for static inheritance.
Interview answer
“Classes are sugar over constructor functions and prototypes. Methods live on Class.prototype; fields usually on the instance. extends chains prototypes; super calls the parent. I still think about this-binding when passing methods as callbacks, and I use private fields for encapsulation instead of underscore conventions.”
Related
Static blocks and inheritance of statics
class Config {
static defaults = { theme: 'light' };
static {
// runs once at class evaluation
this.frozen = Object.freeze({ ...this.defaults });
}
}
class AdminConfig extends Config {}
AdminConfig.defaults; // inherited static via prototype chain on the constructor
extends sets up two chains: instance prototypes and constructor statics. super.staticMethod() works inside static methods. Prefer composition (inject collaborators) when inheritance trees get deeper than one or two levels — JS classes don’t fix deep hierarchy design problems.
class Service {
constructor(deps) {
this.deps = deps;
}
}
// clearer than SuperService → MegaService → Service soup
Further reading
Related guides
- Prototypal InheritanceHow JS objects delegate via [[Prototype]] — chains, Object.create, constructors, classes as sugar, own vs inherited props, and common footguns.
- AbortControllerCancel fetch and other async work with AbortController and AbortSignal — timeouts, race conditions, and cleanup when components unmount.
- Array find, some, every, includesShort-circuiting array predicates: find, findIndex, some, every, and includes — when to use each and common interview traps.
- Array map, filter, reducemap, filter, and reduce as the core transform toolkit — immutability, chaining costs, reduce patterns, and when a plain loop is clearer.
- Arrow Functions Deep DiveLexical this, no arguments object, no construct, concise bodies — when arrows help and when methods and generators need classic functions.