completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Constructors & new

Create many similar JavaScript objects from one function, understand what new does, guard constructors with new.target, and predict constructor return values.

By the end, you can
  • 01
    Make many similar objectsWrite a constructor function, with a capital name, that stores values on this.
  • 02
    Follow the steps of newExplain the four steps: make an empty object, link it to the prototype, run the function with this set to it, and give it back.
  • 03
    Handle the unusual casesUse new.target to catch a missing new, predict what a constructor's return does, and avoid wrapper objects.

One recipe, many objects

An object literal is the curly-brace way to write one object, like { name: "Ada" }. It is great when you need just one object.

But apps often need many objects with the same shape. Think of many users, many books, or many items in a shopping cart. Each one has the same property names, but different values.

A constructor function is a function that makes these objects for you. You write it once. Then you call it again for each new object. Constructor functions are an older JavaScript pattern, and you still see them in a lot of code.

You call a constructor with the word new, like new User("Ada"). In short, this is what happens:

  • JavaScript makes a new, empty object.
  • Inside the constructor, this means that new object.
  • The constructor writes properties onto this.
  • new gives the finished object back to you.

This lesson uses two things you already know. The first is functions, from Declaring & calling functions. The second is methods, where this is the object before the dot.

Real-life analogyCookie cutter plus fresh dough

A constructor is like a cookie cutter. Calling it with new is like pressing the cutter into fresh dough. Every press makes a new cookie with the same shape. But each cookie can have its own sprinkles.

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 that new gives back
In real life: Sprinkles on one cookie
In JavaScript: Values stored on one object, like name and role
Classes do the same job in modern code

Modern JavaScript usually writes this pattern with classes. A class is a newer way to write a constructor. It works the same way inside: new makes an object and links it to shared methods. Later lessons cover this in detail: The prototype chain, F.prototype & constructors, and Class basics. This lesson gives you the base for them.

Constructor functions

FOUNDATION

A constructor function is a normal function. The only difference is how you call it: with new.

By habit, its name starts with a capital letter: User, Book, Task. JavaScript does not need the capital. It is a sign for people who read the code: "call this with new."

Two users from one constructorPop out in the code editor (opens in a new tab)JavaScript
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 starts the User constructor. It takes one input, name.
  • Lines 2 and 3 write two properties onto this: name and role.
  • On line 6, new makes a new, empty object. Then it runs User with this set to that object. So the object in ada gets its own name and role.
  • Line 7 calls the same constructor again. This makes a second, different object, for Grace.
  • Line 8 prints Ada Grace. Line 9 prints false, because they are two different objects.
One User function card at the top. Arrows lead to two carts. The ada cart holds name Ada. The grace cart holds name Grace.User()name: "Ada"adanew User("Ada")name: "Grace"gracenew User("Grace")
One User function, called twice with new, makes two separate objects. Each object keeps its own name, so ada === grace is false.
A constructor can fill in a defaultPop out in the code editor (opens in a new tab)JavaScript
function Task(title) {
  this.title = title || "Untitled";
}

const task = new Task("");
console.log(task.title);

A constructor can also check an input before it stores it. On line 2, title || "Untitled" means: use title, but if it is empty, use "Untitled" instead.

Line 5 passes an empty title, so the task's title becomes "Untitled". That value is stored on this one task only.

Three things to remember from this section:

  • ada.name is "Ada" and grace.name is "Grace". Each object keeps its own values.
  • ada === grace is false. Each new call makes a separate object.
  • You can't use an arrow function with new. Arrow functions can't be constructors, and they don't have their own this.
Forgetting new

If you call User("Ada") without new, no new object is made. What happens next depends on the mode the code runs in:

  • In strict mode, this is undefined. Strict mode is the safer mode that modules and classes always use. So this.name = name tries to write to undefined and throws a TypeError.
  • In older, non-strict scripts, this is the global object, which every script on the page shares. So the same line quietly creates a global name. That is worse, because nothing warns you.

What new does

STEP THROUGH

Here is what new User("Ada") does, in four steps. These steps are for a constructor function like User. (A class that extends another class follows slightly different steps. A later lesson covers that.)

  1. Make a new, empty object.
  2. Link that object to User.prototype, an object where shared methods live. You'll see what the link does below.
  3. Run User with this set to the new object.
  4. Give back the new object. The one exception: if User returns its own object, new gives back that object instead.
new User Ada, left to right. An empty object card. An arrow to the same object with name Ada written on it by User. An arrow to a box called ada that now holds the object.new User("Ada"){ }empty object{ name: "Ada" }User fills this{ name: "Ada" }adaada gets it
Steps 1, 3, and 4 of new: make an empty object, let User fill it through this, then give it back. Step 2, the link to User.prototype, is in the picture under "Shared methods".
Real-life analogyThe bakery routine

Think of new as a bakery's routine. First the baker grabs a fresh tray and stamps the shop logo on it. Then your recipe decorates the pastry. Last, the baker hands the pastry to the customer. Your constructor only does the decorating. The bakery does the other three steps for you.

In real life: Grab a fresh tray
In JavaScript: Make a new, empty object
In real life: Stamp the shop logo on it
In JavaScript: Link it to User.prototype
In real life: Decorate the pastry
In JavaScript: Run User with this set to the object
In real life: Hand it to the customer
In JavaScript: Give back the finished object

Step 2, the link, is easy to miss. This code shows what it does.

A method found through the prototype linkPop out in the code editor (opens in a new tab)JavaScript
function User(name) {
  this.name = name;
}
User.prototype.describe = function () {
  return this.name + " is here";
};

const ada = new User("Ada");
console.log(ada.describe());
console.log(Object.hasOwn(ada, "describe"));
  • Line 4 puts a describe method on User.prototype. It does not put it on ada.
  • Line 10 uses Object.hasOwn(ada, "describe"). It asks: is describe stored on ada itself? The answer is false.
  • Yet line 9, ada.describe(), still works and prints Ada is here.

Why does line 9 work? When JavaScript can't find a property on the object itself, it follows the link to User.prototype and looks there.

The replay below copies the four steps by hand, in a small function called createWith. It is only a model to help you see the steps. In real code, you just use new. It uses a few tools you may not have seen yet:

  • ...args collects the extra inputs into an array called args.
  • Object.create(proto) makes a new, empty object linked to proto. That is steps 1 and 2.
  • Constructor.apply(obj, args) runs the function with this set to obj, and passes in the values from args. That is step 3.
  • Lines 4 to 6 are step 4. If the constructor returned an object or a function, give that back. If not, give back obj.
  • Object.getPrototypeOf(x) tells you which object x is linked to.
  • x instanceof User checks whether x is linked to User.prototype.

The last three lines compare createWith(User, "Ada") with real new User("Ada"). Both objects have the same name and the same link, so all three lines print true.

Copy the four steps of new by hand
Step 0 of 7Ready
Your turn: follow the blue line

This model copies the four steps of new: make an object, link it, run the constructor, give it back. Real code just uses new.

Running in
  1. script
Next: line 2
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);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

new.target

INTERACTIVE

Inside a function written with the function keyword, you can read new.target. It tells you how the function was called:

  • Called with new, new.target is the function itself.
  • Called without new, new.target is undefined.
Check how a function was calledPop out in the code editor (opens in a new tab)JavaScript
function showCall() {
  console.log(new.target ? "constructor call" : "plain call");
}

showCall();
new showCall();
  • Line 2 uses condition ? a : b. It means: if the condition is true, use a. If not, use b.
  • Line 5 calls showCall() without new, so it prints "plain call".
  • Line 6 calls it with new, so it prints "constructor call".

The code inside the function is the same both times. Only new.target changes.

A constructor can use this to catch a missing new. It has two choices:

  • Fix the call: if (!new.target) return new SafeUser(name). The ! means "not", so this line runs when new was left out. It calls the function again, this time with new.
  • Stop with an error: throw a TypeError, so the mistake shows up right away. Exercise 4 practices this.

The replay below uses the first choice. Pick the call on line 8, then step through it.

Watch new.target change
Step 0 of 6Ready
Your turn: follow the blue line

Switch the call to see new.target change. It is undefined when you leave out new, and the function itself when you use new.

Running in
  1. script
Next: line 8
function SafeUser(name) {  if (!new.target) {    return new SafeUser(name);  }  this.name = name;} console.log(ada.name);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Choose the call on line 8

Changing the call starts the replay again. Before you step, guess: will the guard on line 3 run?

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Returning from constructors

EDGE CASES

Most constructors don't have a return line. They write to this, and new gives back that object.

But a constructor can return something. Then one unusual rule applies:

  • If it returns an object, that object takes the place of the object new made.
  • If it returns a primitive, new ignores it. A primitive is a simple value that is not an object: a number, a string, a boolean, null, undefined, a symbol, or a bigint.
An object return wins; a string return is ignoredPop out in the code editor (opens in a new tab)JavaScript
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);
  • Line 3 returns an object. So line 11 prints replacement, not built.
  • Line 8 returns a string. new ignores it, so line 12 prints built.
Left: the constructor returns an object, so the result box holds that object, name replacement. Right: it returns the string ignored, so the result box holds the object new made, name built.return { ... }name: "replacement"resultthe returned objectreturn "ignored"name: "built"resultthe object new made
Left: the constructor returns an object, so you get that object instead of the one new made. Right: it returns a string, a primitive, so new ignores it and you get the object it made.
A number return is ignoredPop out in the code editor (opens in a new tab)JavaScript
function Ticket(code) {
  this.code = code;
  return 0;
}

console.log(new Ticket("A1").code);

Line 3 returns 0, a number. new ignores it and keeps the ticket it made, so line 6 prints A1.

The table sums up the rule. Read each row as: "when the constructor does this, new gives back that."

What new gives back for each kind of return
What the constructor doesWhat new gives backWhy
It has no return line.The object new made.new User("Ada") gives back the object that this pointed to.
It returns a primitive, like "ignored" or 0.The object new made.new ignores the primitive and keeps its own object.
It returns an object.That returned object.return { name: "replacement" } takes the place of the object new made.
It returns a function.That returned function.Functions are objects too, so a returned function also takes the place of the new object.

You will rarely need this rule in your own constructors. But it helps you read unusual library code and answer quiz puzzles. A quick check:

  • The constructor returns an object or a function: you get that instead.
  • It returns a number, string, boolean, null, or undefined: you get the object new made.

Shared methods and the prototype link

COMPARE

You can put a method inside the constructor, with this.greet = function () { ... }. That works. But then each new call makes a brand-new copy of the function, and every object carries its own copy. That uses more memory. And two copies are never equal: === says false.

The better place is the prototype, like User.prototype. A method there is written once, and every object made by new User can use it.

A copied method and a shared methodPop out in the code editor (opens in a new tab)JavaScript
function CopiedMethodUser(name) {
  this.name = name;
  this.greet = function () {
    return "Hi, " + this.name;
  };
}

function SharedMethodUser(name) {
  this.name = name;
}
SharedMethodUser.prototype.greet = function () {
  return "Hi, " + this.name;
};

const copiedA = new CopiedMethodUser("Ada");
const copiedB = new CopiedMethodUser("Grace");
const sharedA = new SharedMethodUser("Ada");
const sharedB = new SharedMethodUser("Grace");
console.log(copiedA.greet === copiedB.greet);
console.log(sharedA.greet === sharedB.greet);
console.log(sharedA.greet());
  • Lines 3 to 5 make a new greet function inside each CopiedMethodUser object.
  • Lines 11 to 13 put one greet function on SharedMethodUser.prototype.
  • Line 19 prints false: the two copied objects hold two different functions.
  • Line 20 prints true: the two shared objects use the same function.
  • Line 21 prints Hi, Ada.
A shorter shared-method examplePop out in the code editor (opens in a new tab)JavaScript
function User(name) {
  this.name = name;
}
User.prototype.sayHi = function () {
  return "Hi, " + this.name;
};

console.log(new User("Asha").sayHi());

Line 4 puts sayHi on User.prototype. Line 8 makes a user and calls sayHi() on it, which prints Hi, Asha.

This works because of step 2 of new: the link. Take sharedA.greet(). JavaScript looks for greet on sharedA itself and doesn't find it. So it follows the link to SharedMethodUser.prototype and finds greet there.

Inside greet, this is sharedA, the object before the dot. So one shared function can still greet each user by name. The prototype lessons later show this lookup in full.

A box called prototype holds one greet function card. Two carts below, sharedA with name Ada and sharedB with name Grace, each have an arrow up to the prototype box.SharedMethodUser.prototypegreet()prototypelinklinkname: "Ada"sharedAname: "Grace"sharedB
greet() is stored once, on SharedMethodUser.prototype. Each object made by new keeps only its own name, plus a link to the prototype. sharedA.greet() follows that link to find greet.

The table compares three places to write a method. Read each row as: "if I write the method here, this is what happens."

Where a constructor's methods can live
Where you write the methodDo two objects share it?When to use it
Inside the constructor: this.greet = function () { ... }No. a.greet !== b.greet, because each object gets its own copy.Rarely. Only when each object needs a function with its own private variables.
On the prototype: User.prototype.greet = function () { ... }Yes. a.greet === b.greet, because both find the same function.Most methods. The one shared function uses this to work on the object that called it.
In a class: class User { greet() { ... } }Yes. Class methods are also stored on the prototype.Modern code. The Class basics lesson teaches this later.

Built-in constructors and wrapper traps

SORT

JavaScript comes with its own constructors too. They are called built-in constructors. For example:

  • new Date() makes a Date object for the current date and time.
  • new Map() makes a Map: a collection of keys and values. A later lesson covers it.

But three built-ins are traps when you use them with new: new Number(5), new String("x"), and new Boolean(false). Each one makes a wrapper object: an object with a primitive value inside it. Code that expects a plain number, string, or boolean can then go wrong.

A wrapper is an object, not a plain valuePop out in the code editor (opens in a new tab)JavaScript
console.log(typeof new String("x"));
console.log(Boolean(new Boolean(false)));
console.log(typeof "x");
console.log(Boolean(false));
  • Line 1 prints object, not string.
  • Line 2 prints true, even though the wrapper holds false.
  • Lines 3 and 4 show the plain values for comparison. They print string and false.

The worst trap is new Boolean(false). The value inside is false. But the wrapper itself is an object, and every object counts as true in an if. Values that count as true are called truthy. So if (new Boolean(false)) runs its block.

Use plain values instead: 5, "x", and false. To convert a value, call Number(value), String(value), or Boolean(value) without new. Called that way, they give back plain values.

Call String and Boolean without new to convertPop out in the code editor (opens in a new tab)JavaScript
console.log(String(5));
console.log(Boolean(""));
console.log(typeof String(5));

Line 1 turns the number 5 into the string "5". Line 2 prints false, because an empty string counts as false. Line 3 prints string: the result is a plain string, not an object.

Needs new, no new needed, or avoid new?
  • A Date object for the current time: new Date()
  • A Map collection: new Map()
  • Your own User constructor
  • Turn text into a number: Number("5")
  • Make an array from a list of items: Array.from(items)
  • A text value: new String("x")
  • A true/false value: new Boolean(false)
  • One small record: { name: "Ada" }
Try it yourself
0 of 8 correct

Sort each case by how you should write it in everyday JavaScript. Each explanation points out the trap.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Where you’ll use this

You will meet constructors in three places:

  • Older code and some libraries still use constructor functions.
  • Built-in objects such as Date, Map, Set, URL, and many browser objects are made with new.
  • Classes use the same steps, with neater syntax.
A cart item with a guard and a shared methodPop out in the code editor (opens in a new tab)JavaScript
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());
  • Line 2 is a new.target guard. If someone forgets new, it calls the constructor again with new.
  • Lines 3 to 5 store the item's name, price, and quantity on this.
  • Lines 8 to 10 put one shared total method on the prototype. It multiplies the price by the quantity.
  • Line 12 makes 3 apples at 2 each. Line 13 prints 6.

Constructors aren't the only way to make objects. Object literals, functions that return objects (called factory functions), and classes are all useful too.

Constructors are still worth learning. They explain the common new Something() code, and they prepare you for prototypes and classes.

Common misconceptions

“A constructor is a special kind of declaration.”

No. It is usually a normal function. What changes is the call: with new, JavaScript makes an object and runs the function on it.

“The capital letter makes new work.”

No. The capital letter is only a habit that helps people read the code. JavaScript doesn't check it.

“new copies prototype methods into every object.”

No. Nothing is copied. new links the object to Constructor.prototype. When a method isn't on the object itself, JavaScript follows that link to find it.

“Returning anything from a constructor replaces the new object.”

No. Only a returned object or function takes its place. A returned primitive, like a number or a string, is ignored.

“new Boolean(false) behaves like false.”

No. It is an object, and every object is truthy, so it counts as true in an if. Don't use wrapper constructors for plain values.

Two questions for constructor puzzles

When a constructor puzzle confuses you, ask two questions. Did the call use new? Did the constructor return an object? Those two answers predict most results.

Practice: constructors and new

5 EXERCISES
Exercise 1 · Warm-upWrite a Book constructor

Write a Book constructor that stores a title and an author. Then make one book and print it.

Starter codePop out in the code editor (opens in a new tab)JavaScript
function Book(title, author) {
  this.title = title;
  this.author = author;
}

const dune = new Book("Dune", "Frank Herbert");
console.log(dune.title + " by " + dune.author);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticePredict two separate objects

    Predict the two lines this prints. The first uses === to ask "same object?". The second uses instanceof to ask "made by Pet?".

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    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);

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeFix a missing new

      A teammate wrote Task("Ship lesson") without new. Add a guard that fixes the call.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function Task(title) {
        if (!new.target) return new Task(title);
        this.title = title;
      }
      
      const task = Task("Ship lesson");
      console.log(task.title);

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeRequire new with an error

        Write an Account constructor that throws a helpful TypeError when someone forgets new.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function Account(name) {
          if (!new.target) {
            throw new TypeError("Use new with Account");
          }
          this.name = name;
        }
        
        console.log(new Account("Ada").name);

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengePredict a returned object

          Predict what this prints. The constructor writes to one object but returns another.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function Ticket() {
            this.code = "A1";
            return { code: "VIP" };
          }
          
          console.log(new Ticket().code);

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS

            Read each snippet carefully. Your first try counts, and every choice explains why it is right or wrong.

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7How do people usually name constructor functions?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the User constructor print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function User(name) {
                this.name = name;
              }
              const ada = new User("Ada");
              console.log(ada.name);

              Choose an answer to see the explanation.

            3. Question 3 of 7Which step is not part of what new User("Ada") does?

              Choose an answer to see the explanation.

            4. Question 4 of 7This constructor returns a string. What does it print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function Box() {
                this.label = "fresh";
                return "ignored";
              }
              console.log(new Box().label);

              Choose an answer to see the explanation.

            5. Question 5 of 7This constructor returns an object. What does it print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function Box() {
                this.label = "fresh";
                return { label: "replacement" };
              }
              console.log(new Box().label);

              Choose an answer to see the explanation.

            6. Question 6 of 7Inside a function written with function, what is new.target when you call it without new?

              Choose an answer to see the explanation.

            7. Question 7 of 7What do these wrapper objects print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(typeof new String("x"));
              console.log(Boolean(new Boolean(false)));

              Choose an answer to see the explanation.

            Key takeaways

            • A constructor function is a normal function that you call with new. By habit, its name starts with a capital letter.
            • new makes an empty object, links it to Constructor.prototype, runs the function with this set to that object, and gives the object back.
            • new.target is undefined when you forget new, and the function itself when you use new. A constructor can use it to catch the mistake.
            • If a constructor returns an object, you get that object instead. If it returns a primitive, new ignores it.
            • Put shared methods on the prototype (or in a class, later). Don't use new with Number, String, or Boolean.

            Remember the one-liner.
            A constructor plus new is a recipe you can reuse to make many separate objects with the same shape.

            Up next: Object.keys, values & entries.

            CompleteFrontend Clear concepts. Working examples.