Constructors & new
Create many similar JavaScript objects from one function, understand what new does, guard constructors with new.target, and predict constructor return values.
- 01Build similar objectsWrite a capitalized constructor function that assigns properties to
this. - 02Trace
newExplain the fresh object, prototype link,thisbinding, and return rule. - 03Handle edge casesUse
new.target, predict constructor returns, and avoid wrapper-object traps.
One recipe, many objects
An object literal is perfect when you need one object: { name: "Ada" }. But apps often need many objects with the same shape: many users, many books, many tasks, many cart items. A constructor function is an older JavaScript pattern for making those similar objects from one reusable function.
You call a constructor with the new operator. The constructor receives a fresh object as this, writes properties onto it, and gives that object back. If you already know functions, Declaring & calling functions, and methods where this is the object before the dot, this lesson connects those ideas to object creation.
A constructor is a cookie cutter. new is the press into fresh dough. Every press makes a new cookie with the same shape, but each cookie can have its own sprinkles: ada.name is separate from grace.name.
- In real life: The cookie cutter
- In JavaScript: The constructor function, such as
User - In real life: Pressing the cutter into dough
- In JavaScript: Calling it with
new User(...) - In real life: Each cookie
- In JavaScript: Each separate object returned by
new - In real life: Sprinkles on one cookie
- In JavaScript: Own properties like
nameandrole
Where the analogy stops: A cookie cutter stamps physical dough. A constructor runs code, so it can validate inputs, choose defaults, and even return a different object.
Modern JavaScript usually writes this pattern with classes. Classes are built on the same idea: a constructor call creates an object and links it to shared behavior. Stage 5 has separate lessons for The prototype chain, F.prototype & constructors, and Class basics; this lesson gives you the foundation.
Constructor functions
FOUNDATIONA constructor function is just a regular function that is meant to be called with new. By convention its name starts with a capital letter: User, Book, Task. The capital is not required by the language, but it tells humans, “use new here.”
function User(name) {
this.name = name;
this.role = "learner";
}
const ada = new User("Ada");
const grace = new User("Grace");
console.log(ada.name, grace.name);
console.log(ada === grace);Line 1 defines the constructor. Lines 2 and 3 write properties on this. When line 6 runs, new supplies a fresh object as this, so ada gets its own name and role. Line 7 presses the same cookie cutter again, making a different object for Grace.
ada.nameis"Ada";grace.nameis"Grace".ada === graceisfalsebecause eachnewcall returns a separate object.- Arrow functions cannot be used with
new, because arrows do not have constructor behavior or their ownthis.
In strict code, calling User("Ada") without new makes this be undefined, so this.name = name throws a TypeError. In sloppy classic scripts, the same mistake can write a global property instead. The tests for this lesson prove both behaviors with real JavaScript.
What new does
STEP THROUGHThe new operator is a small routine with four important steps:
- Create a fresh empty object.
- Link that object to
Constructor.prototype. - Call the constructor with
thisset to the fresh object. - Return the fresh object, unless the constructor returns its own object.
Think of new as a bakery routine. Before your constructor decorates anything, the bakery has already grabbed a fresh tray and stamped it with the shop’s logo. Then your function adds the details and hands the pastry over.
- In real life: Grab a fresh tray
- In JavaScript: Create a new empty object
- In real life: Stamp the shop logo on it
- In JavaScript: Link it to
Constructor.prototype - In real life: Decorate the pastry
- In JavaScript: Run the constructor with
thisset to the object - In real life: Hand it to the customer
- In JavaScript: Return the constructed object
Where the analogy stops: Real bakeries do not have prototype chains. The logo stamp is only a memory aid for JavaScript’s shared-method lookup.
The replay below uses a real hand-written helper named createWith. It is a teaching model, not a replacement for new. The tests prove that this helper and real new User("Ada") produce equivalent objects: same own property, same prototype, and instanceof is true.
This helper is a teaching model of new: create, link, call, return. Step through it beside the real new User("Ada") result.
script
function createWith(Constructor, ...args) { const result = Constructor.apply(obj, args); return result !== null && (typeof result === "object" || typeof result === "function") ? result : obj;} function User(name) { this.name = name;} const real = new User("Ada");const model = createWith(User, "Ada");console.log(real.name === model.name);console.log(Object.getPrototypeOf(real) === Object.getPrototypeOf(model));console.log(model instanceof User);new.target
INTERACTIVEInside a normal function, new.target tells you how the function was started. If the call used new, it is the constructor function. If the call did not use new, it is undefined.
That gives constructors a way to fail clearly or auto-correct. This version auto-corrects: if (!new.target) return new SafeUser(name). Some codebases prefer throwing a TypeError so bugs are noticed immediately.
Switch the setting to see how new.target changes. It is undefined for a normal call and the constructor function for a new call.
script
function SafeUser(name) { if (!new.target) { return new SafeUser(name); } this.name = name;} console.log(ada.name);Returning from constructors
EDGE CASESMost constructors do not write return. They assign to this, and new returns that object. But JavaScript has one unusual rule: returning an object replaces the fresh object, while returning a primitive is ignored.
function ReturnsObject() {
this.name = "built";
return { name: "replacement" };
}
function ReturnsPrimitive() {
this.name = "built";
return "ignored";
}
console.log(new ReturnsObject().name);
console.log(new ReturnsPrimitive().name);| Constructor body | What new returns | Why |
|---|---|---|
| No explicit return | the new object | new User("Ada") returns the object that this received |
| Return a primitive | the new object | return "ignored" is ignored by new |
| Return an object | that returned object | return { name: "replacement" } replaces the fresh object |
| Return a function | that function object | Functions are objects, so they replace the fresh object too |
This is rare in everyday constructors, but it explains weird library code and some interview puzzles. If you see a constructor returning an object, read that line as “replace the cookie.” If it returns a number, string, boolean, null, or undefined, new keeps the object it already made.
Built-in constructors and wrapper traps
SORTJavaScript has built-in constructors too. new Date() creates a Date object. new Map() creates a keyed collection you will study in a later lesson. But new Number(5), new String("x"), and new Boolean(false) create wrapper objects, and those are usually a trap.
console.log(typeof new String("x"));
console.log(Boolean(new Boolean(false)));
console.log(typeof "x");
console.log(Boolean(false));The dangerous one is new Boolean(false). The value inside it represents false, but the wrapper itself is an object, and all objects are truthy. Prefer primitives: 5, "x", and false, or use Number(value), String(value), and Boolean(value) as plain conversion functions.
- Date object for a timestamp:
new Date() - Map collection:
new Map() - Your
Userconstructor - Number parsing:
Number("5") - Make an array from an iterable:
Array.from(items) - Text value:
new String("x") - Boolean value:
new Boolean(false) - One small record:
{ name: "Ada" }
Sort each case by how you should call it in everyday JavaScript. The explanations point out the traps.
Where you’ll use this
You will meet constructor behavior in three places. First, older code and some libraries still expose constructor functions. Second, built-in data structures such as Date, Map, Set, URL, and many browser objects are constructed with new. Third, classes use the same construction pathway with a cleaner syntax.
function CartItem(name, price, quantity) {
if (!new.target) return new CartItem(name, price, quantity);
this.name = name;
this.price = price;
this.quantity = quantity;
}
CartItem.prototype.total = function () {
return this.price * this.quantity;
};
const apples = new CartItem("Apples", 2, 3);
console.log(apples.total());This is not the only way to model data. Object literals, factory functions, and classes are all useful. Constructors are worth learning because they explain the common new Something() shape and prepare you for prototypes and classes.
Common misconceptions
“A constructor is a special kind of declaration.”
It is usually an ordinary function used with new. The call site changes what happens.
“The capital letter makes new work.”
The capital letter is only a convention for humans. JavaScript does not enforce it.
“new copies prototype methods into every object.”
No copy happens. new creates a link to Constructor.prototype, and property lookup can follow that link.
“Returning anything from a constructor replaces the instance.”
Only object and function returns replace it. Primitive returns are ignored.
“new Boolean(false) behaves like false.”
It is an object, so it is truthy. Avoid wrapper constructors for primitives.
If a constructor puzzle confuses you, ask two questions: did the call use new, and did the constructor return an object? Those two answers predict most of the result.
Practice: constructors and new
5 EXERCISESCreate a Book constructor with title and author, then construct one book and print it.
function Book(title, author) {
this.title = title;
this.author = author;
}
const dune = new Book("Dune", "Frank Herbert");
console.log(dune.title + " by " + dune.author);function Book(title, author) {
this.title = title;
this.author = author;
}
const dune = new Book("Dune", "Frank Herbert");
console.log(dune.title + " by " + dune.author);new Book(...) supplies a fresh this. The constructor writes title and author, so the final log prints Dune by Frank Herbert.
Predict the two output lines. This checks both identity with === and membership with instanceof.
function Pet(name) {
this.name = name;
}
const a = new Pet("Mochi");
const b = new Pet("Mochi");
console.log(a === b);
console.log(a instanceof Pet);The first line prints false because a and b are different objects even though their properties match. The second prints true because a was created by new Pet(...).
A teammate wrote Task("Ship lesson") without new. Add a guard that auto-corrects the call.
function Task(title) {
if (!new.target) return new Task(title);
this.title = title;
}
const task = Task("Ship lesson");
console.log(task.title);function Task(title) {
if (!new.target) return new Task(title);
this.title = title;
}
const task = Task("Ship lesson");
console.log(task.title);The guard notices a plain call and immediately re-runs the constructor with new, so Task("Ship lesson") still returns a Task object.
Write an Account constructor that throws a helpful TypeError when someone forgets new.
function Account(name) {
if (!new.target) {
throw new TypeError("Use new with Account");
}
this.name = name;
}
console.log(new Account("Ada").name);function Account(name) {
if (!new.target) {
throw new TypeError("Use new with Account");
}
this.name = name;
}
console.log(new Account("Ada").name);This version chooses fail-fast behavior. A plain Account("Ada") would throw TypeError: Use new with Account; the valid constructor call prints Ada.
Predict what the constructor returns when it assigns one object but returns another.
function Ticket() {
this.code = "A1";
return { code: "VIP" };
}
console.log(new Ticket().code);new Ticket() first creates an object with code: "A1", but the explicit object return replaces it. The printed code is VIP.
Quiz: check your understanding
7 QUESTIONSRead each snippet carefully. Your first try counts, but every option explains why it is right or wrong.
Question 1 of 7What is the usual naming convention for constructor functions?
Choose an answer to see the explanation.
Question 2 of 7What does the User constructor print?
Read the code, then predictfunction User(name) { this.name = name; } const ada = new User("Ada"); console.log(ada.name);Choose an answer to see the explanation.
Question 3 of 7Which step is not part of what
new User("Ada")does?Choose an answer to see the explanation.
Question 4 of 7What does a primitive-returning constructor print?
Read the code, then predictfunction Box() { this.label = "fresh"; return "ignored"; } console.log(new Box().label);Choose an answer to see the explanation.
Question 5 of 7What does an object-returning constructor print?
Read the code, then predictfunction Box() { this.label = "fresh"; return { label: "replacement" }; } console.log(new Box().label);Choose an answer to see the explanation.
Question 6 of 7Inside a normal function, what is
new.targetwhen the function was called withoutnew?Choose an answer to see the explanation.
Question 7 of 7What do wrapper constructors print?
Read the code, then predictconsole.log(typeof new String("x")); console.log(Boolean(new Boolean(false)));Choose an answer to see the explanation.
Key takeaways
- Constructor functions are regular functions intended to be called with
new; capitalize their names by convention. newcreates a fresh object, links it toConstructor.prototype, calls the function withthisset to that object, and returns it.new.targetisundefinedfor plain calls and the constructor fornewcalls, so it can guard mistakes.- Returning an object from a constructor replaces the fresh object; returning a primitive is ignored.
- Put shared methods on the prototype or use class syntax later; avoid primitive wrapper constructors.
Remember the one-liner.
A constructor plus new is a reusable recipe for making separate objects with the same shape.
Up next: Object.keys, values & entries.