A Class Is a Blueprint for Objects
A class describes the shape and behavior of a kind of object. You define the blueprint once, then stamp out as many instances as you need. Each instance carries its own data but shares the same methods.
The basic shape:
class User { ... } defines the blueprint. new User(...) creates an instance. Each instance gets its own name and email, but both share the single greet method defined on the class.
Two instances, two sets of data, one set of methods. That's the whole idea.
The constructor Sets Up Each Instance
The constructor is a special method that runs exactly once per instance, right when new creates it. Its job is to initialise the fresh object — usually by copying arguments onto this:
this inside the constructor refers to the brand-new instance being built. Assigning this.x = x puts x on that specific object. Every new Point(...) call gets its own this, so its own x and y.
If you don't write a constructor, JavaScript gives you an empty one for free. You only need to write one when you actually have setup to do.
new Is What Makes the Machinery Work
A class call without new throws:
const p = Point(3, 4);
// TypeError: Class constructor Point cannot be invoked without 'new'
That's deliberate. new does four things in order:
- Creates a fresh empty object.
- Links it to the class's prototype (where the methods live).
- Runs the
constructorwiththisbound to the new object. - Returns the new object.
Without new, none of that happens. The class enforces the rule so you can't accidentally forget it — a real improvement over the pre-class days, when forgetting new would quietly corrupt the global object.
Methods Are Shared, Fields Are Per-Instance
Methods defined inside the class body live on the prototype — one copy shared by every instance. Instance fields (anything you assign to this) are per-instance, separate copies each time.
Both instances have their own count, so incrementing one doesn't affect the other. But a.increment and b.increment are literally the same function — stored once on the prototype, looked up whenever you call it on an instance. That's why classes scale cheaply: a thousand instances don't make a thousand copies of each method.
Class Fields
You can declare instance fields at the top of the class body, outside the constructor:
Field declarations run before the constructor body, as if they were written at the top of constructor. They're useful when the initial value doesn't depend on constructor arguments — cleaner than cluttering the constructor with this.count = 0; this.step = 1;.
When values do depend on arguments, keep the assignment in the constructor where the arguments are in scope.
Getters and Setters
A getter or setter looks like a method but behaves like a property access. You read or assign without parentheses, and the method runs underneath:
Note the call sites: t.fahrenheit (no parens) reads the getter, t.fahrenheit = 100 triggers the setter. From the outside, fahrenheit looks like a regular property, but it's computed on the fly from celsius.
Getters are great for derived values. Setters are great for validating or normalising a value on assignment. Don't over-use them — if a getter is expensive, a reader will be surprised that a "property access" is doing real work.
Method Shorthand, Computed Names, and this
Method definitions in a class use shorthand syntax — no function keyword, no : between name and body:
Returning this from add enables method chaining — each call hands back the same instance so the next method can run on it.
One gotcha: methods aren't automatically bound to their instance. If you pull a method off and call it standalone, this is lost:
Calling g.hello() works because the . supplies this. Calling fn() standalone doesn't. If you need a detached, pre-bound method (a common case in event handlers), bind it in the constructor or use an arrow-function class field: hello = () => \Hi, ${this.name}`;`.
A Small Working Example
Pulling the pieces together — fields, constructor, methods, a getter:
Readable at a glance: the class describes exactly what a BankAccount is and what it can do.
Classes Are Functions, Really
One thing worth internalising: class is mostly syntactic sugar. Under the hood, a class is a function — specifically a constructor function — and its methods live on ClassName.prototype:
typeof User is "function". greet lives on User.prototype. Instances look up greet through the prototype chain — the same mechanism that's been in the language since day one. Classes just give you a clean syntax for setting it up.
That mental model pays off later: inheritance, instanceof, and debugging prototype chains all make more sense once you remember a class is a function with methods hanging off its prototype.
Next: Inheritance
So far each class stands alone. Most real designs build class hierarchies — a Dog that's a kind of Animal, an AdminUser that's a kind of User. The extends and super keywords handle that, and they're coming up next.
Frequently Asked Questions
How do you create a class in JavaScript?
Use the class keyword followed by a name, then a block with a constructor method and any other methods. Create an instance with new ClassName(...). Example: class User { constructor(name) { this.name = name; } } then new User('Ada').
What does the constructor do in a JavaScript class?
The constructor runs once when you call new ClassName(...). Its job is to set up the new instance — usually assigning arguments to this as instance properties. If you don't write one, JavaScript gives you an empty default constructor automatically.
What's the difference between a class and a function in JavaScript?
Under the hood, a class is a function — specifically a constructor function with its methods attached to the prototype. The class keyword is mostly syntactic sugar, but it enforces calling with new, supports extends cleanly, and makes methods non-enumerable. For new code, prefer class over hand-written constructor functions.