Constructor, operator "new"
Object literals with {...} are perfect when you need a single object. The trouble starts when you need twenty of them that all share the same shape: a list of users, a set of menu items, a cart full of products. Copy-pasting a literal twenty times is tedious and easy to get wrong.
JavaScript’s answer is the pair of tools we’ll unpack here: constructor functions and the new operator. Together they act like a stamp — write the shape once, then press out as many objects as you want.
Constructor function
A constructor is nothing exotic. It’s an ordinary function. What makes it a “constructor” is a pair of conventions the community agreed on:
- Name it with a capital first letter.
Member, notmember. This is a signal to whoever reads the code, not a rule the engine enforces. - Call it with
new. That’s the switch that turns a plain function call into object creation.
Here’s the canonical example:
function Member(name) {
this.name = name;
this.isPremium = false;
}
let member = new Member("Kira");
alert(member.name); // Kira
alert(member.isPremium); // false
Notice the function never returns anything explicitly, yet user ends up as a fully-formed object. The new keyword is doing work behind the scenes.
What new actually does
When you put new in front of a function call, three steps run automatically:
- A fresh empty object is created and bound to
this. - The function body runs. Typically it hangs properties off
this. thisis returned as the result of the wholenewexpression.
So new Member("Kira") behaves as if the body were written like this, with the commented lines happening for you:
function Member(name) {
// this = {}; (implicitly)
// add properties to this
this.name = name;
this.isPremium = false;
// return this; (implicitly)
}
Which means let member = new Member("Kira") produces exactly the same object you’d get by writing the literal by hand:
let member = {
name: "Kira",
isPremium: false
};
The payoff is reuse. Want more members? new Member("Priya"), new Member("Nadia"), and on it goes. Each call runs the same steps against a fresh object, so you get consistent results with far less typing than repeating a literal every time.
That reuse is the whole point of a constructor: one place that defines how an object gets built. Type a name and press the button below to stamp out a fresh object from the same Member blueprint each time — every click runs the three steps against a new this.
Constructor mode test: new.target
Inside a function you can detect whether it was invoked with new by reading a special new.target property. It’s undefined for a plain call and holds the function itself when called with new:
function Member() {
alert(new.target);
}
// without "new":
Member(); // undefined
// with "new":
new Member(); // function Member { ... }
One practical use: make the function behave the same whether or not the caller remembered new. If someone forgets it, you quietly redirect:
function Member(name) {
if (!new.target) { // called without new?
return new Member(name); // ...add new for the caller
}
this.name = name;
}
let maya = Member("Maya"); // redirects to new Member
alert(maya.name); // Maya
Some libraries do this so their API is forgiving. Use it sparingly, though. When new is present, everyone reading the code knows an object is being constructed. Hide that behind an auto-correct and the intent gets murkier.
Return from constructors
Most constructors have no return at all. They write everything into this, and this becomes the result on its own. But a return statement is legal inside a constructor, and it follows one small rule:
returnwith an object replacesthis— that object comes back instead.returnwith a primitive (or an emptyreturn) is ignored —thisstill comes back.
Here a returned object overrides this:
function BigMember() {
this.name = "Maya";
return { name: "Titan" }; // <-- returns this object
}
alert( new BigMember().name ); // Titan, got that object
And here an empty return changes nothing — you’d get the same result with a primitive after return:
function SmallMember() {
this.name = "Maya";
return; // <-- returns this
}
alert( new SmallMember().name ); // Maya
You’ll rarely lean on this. It’s here so nothing surprises you later — for example, when you read a constructor that returns a cached instance instead of a fresh one.
Try both branches below. Flip the switch to choose what the constructor returns, then build it — an object return wins, while a primitive return is ignored and you get this back instead.
Methods in constructor
Constructors give you a lot of room. The parameters decide what goes into each object, so different arguments produce differently-configured instances from the same blueprint.
And this isn’t limited to data. You can attach functions too, giving each object its own methods.
Here new Member(name) builds an object that carries both a name and a greet method:
function Member(name) {
this.name = name;
this.greet = function() {
alert( "My name is: " + this.name );
};
}
let maya = new Member("Maya");
maya.greet(); // My name is: Maya
/*
maya = {
name: "Maya",
greet: function() { ... }
}
*/
Each object built this way carries its own greet, and inside that method this points at the object it belongs to. Build a couple of users below and greet them — every greeting reports the name of the object whose method you called.
For richer object modeling, there’s a more polished syntax — classes — that we’ll get to later. It’s built on top of the same machinery you just learned.
Summary
- Constructor functions are ordinary functions, distinguished by a naming convention: a capital first letter.
- They’re meant to be called with
new. That call creates an emptythisup front, runs the body, and returns the filled-in object at the end.
Constructors exist to stamp out many similar objects from one definition. JavaScript itself ships plenty of built-in constructors you’ll meet as you go — Date for dates, Set for collections of unique values, Map, and more, all invoked with new.