completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

F.prototype & constructors

Learn how new links objects to a constructor’s prototype, why the constructor property matters, how prototype methods are shared, and how constructor inheritance works.

By the end, you can
  • 01
    Explain F.prototypeSay which object new F() links each new object to, and how JavaScript uses that link to find methods.
  • 02
    Share one methodMove a method out of the constructor and onto F.prototype, so every object uses the same function.
  • 03
    Make one constructor build on anotherConnect Admin to User with User.call, Object.create, and the constructor property.

Where new objects find their shared methods

In the lesson The prototype chain, you saw that every object has a hidden link to one other object. That other object is its prototype. When you read a property the object doesn't have, JavaScript follows the link and looks in the prototype.

This lesson asks one question. When new User("Ada") makes a new object, which object does its hidden link point to?

The answer is User.prototype. Here is how it works:

  • A function written with the function keyword has a property called prototype.
  • That property holds a plain object.
  • When you call the function with new, the new object's hidden link points to that object.

A function you call with new is called a constructor. An object it makes is called an instance. So new User("Ada") makes an instance of User.

Real-life analogyThe workshop shelf

A builder makes many name badges. Each badge has its own name on it. But all the badges use the same tools, such as a "print a greeting" tool. The builder keeps one copy of each tool on a shelf. Nobody glues a copy of every tool onto every badge.

In real life: The person who builds badges
In JavaScript: The constructor function, such as User
In real life: One shelf of tools that every badge uses
In JavaScript: User.prototype
In real life: A finished badge with its own name on it
In JavaScript: An instance, such as ada, with its own name
In real life: Walking back to the shelf to get a tool
In JavaScript: JavaScript finding ada.greet on User.prototype
One-line definition

F.prototype is the object that every new F() instance gets as its prototype.

In this lesson you will use that fact to:

  • share one method between many objects,
  • understand the constructor property,
  • replace F.prototype without surprises,
  • make one constructor build on another one.

The class syntax in the next module makes the same links. It just writes them for you.

The constructor property points back to the function

INTERACTIVE

When JavaScript makes a function, it also makes its prototype object. That object starts with one property, constructor, which points back to the function. So User.prototype.constructor is User.

That is why line 12 of the first example printed true for ada.constructor === User. ada doesn't have her own constructor property. JavaScript finds it on User.prototype.

Real-life analogyThe label on the shelf

The shelf has a label that says which builder it belongs to. If you take the shelf away and put up a new one, the old label does not move to the new shelf by itself.

In real life: A label on the shelf that says “Built by User”
In JavaScript: User.prototype.constructor = User
In real life: A badge looking up at the shelf label
In JavaScript: JavaScript finding ada.constructor on User.prototype
In real life: Putting up a new shelf with no label
In JavaScript: User.prototype = { greet() {} }
Every new prototype object starts with constructorPop out in the code editor (opens in a new tab)JavaScript
function Product(name) {  this.name = name;}console.log(Product.prototype.constructor === Product);

Line 4 prints true. The constructor property is useful to look at, but it is a normal property. It does not build objects, and your code can change it.

Now see what happens when you put a whole new object in User.prototype. Choose whether the new object has constructor: User, then step through.

Put a new object in User.prototype
Step 0 of 8Ready
Your turn: follow the blue line

Choose whether the new object has constructor, then step through to see which object each instance uses.

Running in
  1. script
Next: line 4
function User(name) {  this.name = name;}  return "Old shelf: " + this.name;};const ada = new User("Ada"); User.prototype = {  greet() {    return "New shelf: " + this.name;  },};const lin = new User("Lin"); console.log(ada.greet());console.log(lin.greet());console.log(ada.constructor === User);console.log(lin.constructor === User);
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Does the new prototype object have constructor?

Changing this choice starts the replay again. Watch ada keep the old prototype object.

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.

Two things to remember from this experiment:

  • Putting a new object in User.prototype does not change objects you already made. ada still links to the old object.
  • An object you write with { } does not get constructor: User by itself. If your code reads instance.constructor, add it back when you replace the prototype.
Add a method, or replace the whole objectPop out in the code editor (opens in a new tab)JavaScript
function User(name) {  this.name = name;}User.prototype.greet = function () {  return "Hi, " + this.name;};const ada = new User("Ada");User.prototype.wave = function () {  return "Wave, " + this.name;};console.log(ada.wave());console.log(ada.constructor === User);User.prototype = {  greet() {    return "Hello, " + this.name;  },};const lin = new User("Lin");console.log(ada.greet());console.log(lin.greet());console.log(lin.constructor === User);

Line by line:

  1. Line 8 adds wave to the object that is already in User.prototype. ada links to that object, so she can use wave too.
  2. Line 12 prints true. Adding a method kept the constructor property.
  3. Line 13 puts a brand-new object in User.prototype, with a new greet.
  4. Line 19 prints Hi, Ada. ada still uses the old object.
  5. Line 20 prints Hello, Lin. lin was made after line 13, so he uses the new object.
  6. Line 21 prints false. The new object has no constructor, so JavaScript keeps looking up the chain. It finds Object.prototype.constructor, which is Object.
Add constructor back so Object.keys doesn't list itPop out in the code editor (opens in a new tab)JavaScript
function Product(name) {  this.name = name;}Product.prototype = {  describe() {    return this.name;  },};Object.defineProperty(Product.prototype, "constructor", {  value: Product,  writable: true,  configurable: true,});console.log(Product.prototype.constructor === Product);console.log(Object.keys(Product.prototype).includes("constructor"));

Lines 9 to 13 use Object.defineProperty. It adds a property and lets you set its settings. One setting is enumerable: whether Object.keys and for...in list the property. You didn't set it here, so it is false.

That matches the original constructor property, which is not listed either. Line 14 prints true, and line 15 prints false.

Old objects keep the object they linked toPop out in the code editor (opens in a new tab)JavaScript
function User(name) {  this.name = name;}const ada = new User("Ada");const oldShelf = Object.getPrototypeOf(ada);User.prototype = {};const lin = new User("Lin");console.log(Object.getPrototypeOf(ada) === oldShelf);console.log(Object.getPrototypeOf(lin) === User.prototype);

Line 5 saves the object that ada links to as oldShelf. Line 6 puts a new object in User.prototype. That changes the function's property, but it cannot change the hidden link already stored in ada. Both lines 8 and 9 print true.

After User.prototype = {}. The ada card has an arrow to the old prototype card. The lin card has an arrow to the new prototype card. User.prototype now points to the new prototype card.adaold prototypemade firstlinnew prototypemade afterUser.prototype
ada was made before line 6, so she still links to the old object. Line 6 points User.prototype at a new object, and only lin links to it.
Replacing the prototype changes instanceofPop 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 instanceof User);User.prototype = {};const lin = new User("Lin");console.log(ada instanceof User);console.log(lin instanceof User);

ada instanceof User asks: is the object in User.prototype right now somewhere in ada's chain of links?

  • Line 5 prints true. Nothing has been replaced yet.
  • Line 8 prints false. ada still links to the old object, and User.prototype is now a different one.
  • Line 9 prints true. lin links to the new object.

Share one method instead of copying it

INTERACTIVE

If you write this.greet = function () { ... } inside a constructor, it makes a new function each time the constructor runs. A hundred users get a hundred greet functions that all do the same thing.

If you put the method on F.prototype instead, there is only one function. Every instance finds that same one.

Left: greet made inside the constructor. ada and lin each point to their own greet card, so there are 2 functions. Right: greet put on the prototype. ada and lin both point to one greet card, so there is 1 function.made inside Useradagreet()lingreet()2 functionson User.prototypeadalingreet()1 function
On the left, each call of the constructor makes a new greet. On the right, both objects find the same greet on the prototype.
One describe method, two productsPop out in the code editor (opens in a new tab)JavaScript
function Product(name, price) {  this.name = name;  this.price = price;}Product.prototype.describe = function () {  return this.name + " costs $" + this.price;};const a = new Product("Tea", 3);const b = new Product("Bread", 2);console.log(a.describe());console.log(a.describe === b.describe);
  1. Lines 1 to 4 give each product its own name and price.
  2. Line 5 puts one describe function on Product.prototype.
  3. Line 10 prints Tea costs $3, using Tea's own data.
  4. Line 11 prints true. Both products found the very same function.
Use constructor to make another productPop out in the code editor (opens in a new tab)JavaScript
function Product(name, price) {  this.name = name;  this.price = price;}Product.prototype.describe = function () {  return this.name + " costs $" + this.price;};const item = new Product("Tea", 3);const sibling = new item.constructor("Coffee", 4);console.log(sibling.describe());console.log(sibling.constructor === Product);

On line 9, item.constructor is found on Product.prototype, and it is Product. So new item.constructor("Coffee", 4) makes another product. Line 10 prints Coffee costs $4.

This only works if constructor still points to the right function. If someone replaced the prototype and didn't add it back, item.constructor would be Object.

How many greet functions are made?
Two ways to give users a greet methodPop out in the code editor (opens in a new tab)JavaScript
function UserOwn(name) {  this.name = name;  this.greet = function () {    return "Hi, " + this.name;  };} function UserShared(name) {  this.name = name;}UserShared.prototype.greet = function () {  return "Hi, " + this.name;};
Do the first two users share greet?4 users
  • Made inside the constructorfalse

    4 different greet functions.

  • On the prototypetrue

    1 greet function, shared by all.

Try it yourself
Number of users:

With 4 users, the method made inside the constructor gives 4 different functions. The method on the prototype gives 1.

Both ways work. With the prototype, all users share one greet function, and each user still has its own name.

The table below lists four kinds of things. Read each row as: where is it stored, and how JavaScript finds it.

Where each thing is stored in constructor code
What it isWhere it is storedHow JavaScript finds it
Data such as nameOn each instance.JavaScript finds it right away on ada or lin.
A shared method such as greetOn User.prototype.ada has no greet, so JavaScript follows the link to User.prototype.
The constructor propertyUsually on User.prototype.JavaScript follows the link to find it. If you replace the prototype and don't add it back, it finds Object instead.
A parent methodOn User.prototype, one link past Admin.prototype.JavaScript checks the admin, then Admin.prototype, then User.prototype.

This is why older JavaScript code often adds methods right after the constructor function. The method still gets the instance as this when you call it as ada.greet().

Own property or prototype?
  • ada.name after new User("Ada")
  • maya.level after new Admin("Maya", 2)
  • User.prototype.greet
  • User.prototype.constructor
  • Admin.prototype.greet, the admin's own greet
  • User.prototype.greet when maya calls the parent method
Try it yourself
0 of 6 correct

Sort each property or method by the object it is stored on.

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

One constructor building on another

STEP THROUGH

Sometimes you want a more specific kind of object. An Admin is a User with a level. Admins should get everything users have. This is called inheritance.

Before class existed, code connected two constructors by hand. The usual pattern has three jobs:

  1. Inside Admin, run User.call(this, name). .call(this, ...) runs a function with this set to the object you pass. So User writes name onto the new admin.
  2. Set Admin.prototype = Object.create(User.prototype). Object.create(obj) makes a new empty object whose hidden link points to obj. Now admins can find user methods.
  3. Set Admin.prototype.constructor = Admin, because the new object has no constructor of its own. Then add the admin's own methods.
Build Admin on top of User
Step 0 of 10Ready
Your turn: follow the blue line

Building one constructor on another takes two jobs: call the parent constructor to set the data, and link the child prototype to the parent prototype to share the methods.

Running in
  1. script
Next: line 1
  this.name = name;}User.prototype.greet = function () {  return "Hi, " + this.name;}; function Admin(name, level) {  User.call(this, name);  this.level = level;}Admin.prototype = Object.create(User.prototype);Admin.prototype.constructor = Admin;Admin.prototype.greet = function () {  return User.prototype.greet.call(this) + " (admin " + this.level + ")";}; const maya = new Admin("Maya", 2);console.log(maya.greet());console.log(maya instanceof Admin);console.log(maya 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.

Line 14 puts a new greet on Admin.prototype. It has the same name as the method on User.prototype. This is called overriding: JavaScript finds Admin.prototype.greet first, so it never reaches the user one by itself.

On line 15, User.prototype.greet.call(this) runs the user method on purpose, with the same admin as this. Then it adds (admin 2).

Reading maya.greet(). Three cards in a row joined by arrows: maya, Admin.prototype, and User.prototype. maya holds name and level. Admin.prototype holds a greet that is found first. User.prototype holds the parent greet. The result is "Hi, Maya (admin 2)".maya.greet()mayaAdmin.prototypeUser.prototypename, levelgreet(): found firstgreet(): the parent"Hi, Maya (admin 2)"
Object.create links Admin.prototype to User.prototype. JavaScript finds Admin's greet first, and that greet calls User's greet.
instanceof follows links, not the constructor propertyPop out in the code editor (opens in a new tab)JavaScript
function User(name) {  this.name = name;}function Admin(name) {  User.call(this, name);}Admin.prototype = Object.create(User.prototype);Admin.prototype.constructor = Object;const maya = new Admin("Maya");console.log(maya instanceof Admin);console.log(maya instanceof User);console.log(maya.constructor === Object);

Line 8 sets Admin.prototype.constructor to Object, which is wrong on purpose. Lines 10 and 11 still print true, because instanceof looks at the hidden links, and line 7 made those. Line 12 prints true too: maya.constructor is now Object.

So constructor is only a property you can read. The hidden links are what really connect the objects.

Classes make the same links

COMPARE

You will learn classes in the next module, so you don't need to learn their syntax yet. For now, know two things:

  • Methods written in a class are stored on the class's prototype.
  • extends links the child's prototype to the parent's prototype.
The same Admin, written as classesPop out in the code editor (opens in a new tab)JavaScript
class User {  constructor(name) {    this.name = name;  }  greet() {    return "Hi, " + this.name;  }} class Admin extends User {  constructor(name, level) {    super(name);    this.level = level;  }  greet() {    return super.greet() + " (admin " + this.level + ")";  }} const maya = new Admin("Maya", 2);console.log(maya.greet());console.log(Object.getPrototypeOf(Admin.prototype) === User.prototype);

Line 21 prints the same greeting as the constructor version: Hi, Maya (admin 2). Line 22 prints true, so Admin.prototype links to User.prototype, just like before.

  • super(name) on line 12 does the job of User.call(this, name).
  • super.greet() on line 16 does the job of User.prototype.greet.call(this).
Which functions have a prototype property?Pop out in the code editor (opens in a new tab)JavaScript
console.log((function User() {}).prototype !== undefined);console.log((() => {}).prototype === undefined);const tools = { build() {} };console.log(tools.build.prototype === undefined);class Panel {}console.log(typeof Panel.prototype);
  • Line 1 prints true. A function written with function has a prototype, because you can call it with new.
  • Line 2 prints true. An arrow function can't be called with new, so its prototype is undefined.
  • Line 4 prints true. A method written as build() {} inside an object can't be called with new either.
  • Line 6 prints object. A class has a prototype object.

Where you'll use this

You will meet constructor prototypes when you:

  • read older libraries that use constructor functions,
  • look at objects in DevTools and see their prototype,
  • find out why instanceof gives a surprising answer,
  • make many objects that share the same methods.

Class code is easier to debug too, once you know the links it makes.

Practical checklist
  • Put data that is different for each object, such as name, on the instance.
  • Put methods every object can share, such as greet, on the prototype.
  • If you replace a whole prototype object, add constructor back if any code reads it.
  • For inheritance, do both jobs: call the parent constructor, and link the prototypes.

Common misconceptions

  • “F.prototype is the prototype of F.” No. It is the object that instances made by new F() link to.
  • “Prototype methods are copied into every object.” No. Every object finds the same one by following its link. ada.greet === lin.greet is true.
  • “The constructor property creates the object.” No. It is a normal property, and instances usually find it on the prototype.
  • “Replacing F.prototype changes old objects.” No. Old objects keep the object they already link to.
  • “Calling the parent constructor gives the child its methods.” No. It only sets the fields. Object.create makes the link to the methods.
  • “Classes use a different kind of inheritance.” No. Classes are a shorter way to write the same prototype links.

Practice exercises

5 EXERCISES
Exercise 1 · Warm-upPredict the prototype links

Read the code and work out the answers first. Then type the two printed values.

Starter codePop out in the code editor (opens in a new tab)JavaScript
function User(name) {
  this.name = name;
}
User.prototype.greet = function () {
  return "Hi " + this.name;
};
const ada = new User("Ada");
console.log(Object.getPrototypeOf(ada) === User.prototype);
console.log(ada.hasOwnProperty("greet"));

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

    Exercise 2 · PracticeMove a method to the prototype

    Change the code so all users share one greet function.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    function User(name) {
      this.name = name;
      this.greet = function () {
        return "Hi, " + this.name;
      };
    }

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

      Exercise 3 · PracticeAdd the missing constructor property

      Fix the new prototype object so instances find User when they read constructor.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function User(name) {
        this.name = name;
      }
      User.prototype = {
        greet() {
          return "Hi, " + this.name;
        },
      };

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

        Exercise 4 · ChallengeMake Admin build on User

        Finish the three jobs so an admin is also an instance of User.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function User(name) {
          this.name = name;
        }
        User.prototype.greet = function () {
          return "Hi, " + this.name;
        };
        function Admin(name, level) {
          // initialize User's fields here
          this.level = level;
        }
        // link Admin.prototype here

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

          Exercise 5 · ChallengeRewrite the constructor as a class

          Write the same thing as class User, then check the greeting.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function User(name) {
            this.name = name;
          }
          User.prototype.greet = function () {
            return "Hi, " + this.name;
          };

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

            Check your understanding

            7 QUESTIONS
            F.prototype & constructors quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does new User() do with User.prototype?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does this code print?

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

              Choose an answer to see the explanation.

            3. Question 3 of 7After User.prototype = { greet() {} }, why can new User().constructor === Object be true?

              Choose an answer to see the explanation.

            4. Question 4 of 7Which line connects Admin instances to User.prototype methods?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function Admin(name) {
                User.call(this, name);
              }
              Admin.prototype = Object.create(User.prototype);
              Admin.prototype.constructor = Admin;

              Choose an answer to see the explanation.

            5. Question 5 of 7What does this print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log((() => {}).prototype === undefined);

              Choose an answer to see the explanation.

            6. Question 6 of 7Where should you usually put a method that many instances share?

              Choose an answer to see the explanation.

            7. Question 7 of 7How does class Admin extends User relate to the constructor pattern?

              Choose an answer to see the explanation.

            Key takeaways

            • new F() links the new object to F.prototype.
            • Data that is different for each object goes on the instance. Shared methods go on the prototype.
            • Instances usually find constructor on the prototype. Add it back after you replace the prototype object.
            • For one constructor to build on another, call the parent constructor and link the prototypes.
            • Classes make the same prototype links with shorter code.

            Final definition: F.prototype is the shared object that every new F() instance links to.

            Up next: Built-in prototypes.

            CompleteFrontend Clear concepts. Working examples.