Skip to main content

Command Palette

Search for a command to run...

The `new` Keyword in JavaScript: What Actually Happens Under the Hood

Published
5 min read
The `new` Keyword in JavaScript: What Actually Happens Under the Hood

Assume it's a bread mold; we can just have a template you then pass bread through, which, in this case, is our mold, resulting in producing as many breads as you want. In JavaScript, we have the same thing with the name of a constructor, which is basically a template. Constructors are basically built with the goal of being used with the new keyword.

Constructor Function

Before understanding the new keyword, we first understand the constructor function.

The constructor function is basically similar to a normal function, but built with the intention of being used with the new keyword. This is a convention to write a constructor function with the first character in a capital letter, which is not enforced by JavaScript. Capital letter is for other developers to understand that it is a constructor function.

function Person(name, age) {
  this.name = name;
  this.age = age;
}

If you call this without new, this will either be the global object (in non-strict mode) or undefined (in strict mode). Neither is what you want. The new keyword is what makes this a point to a brand new object.

The working of the new keyword step by step

new is internally doing these steps in sequential order.

Step 1: Create a new empty object
Step 2: Set its [[Prototype]] to the constructor's .prototype
Step 3: Run the constructor function with `this` bound to the new object
Step 4: Return the new object (unless the constructor explicitly returns another object)

Visual Flow

function Person(name, age) {
  this.name = name;
  this.age = age;
}

const pallab = new Person("Pallab", 23);

console.log(pallab.name); // "Pallab"
console.log(pallab.age);  // 23

When new Person("Pallab",23) runs, JavaScript creates a fresh empty object, links its prototype, and runs the Person function with this pointing at that empty object (so this.name = name writes onto it and returns the result. You get back a fully formed object

How Prototype linking works

The second step is where a lot of JavaScript’s power comes from.

When new It connects the object to Person.prototypeIt enables shared behavior through the prototype chain.

User.prototype.describe = function () {
  return `User \({this.username} is at level \){this.level}`;
};

const dev = new User("Ankit", 7);

console.log(dev.describe()); // "User Ankit is at level 7"

Even though dev doesn’t directly contain a describe method, JavaScript looks up the prototype chain when it can’t find a property on the object itself. It finds describe User.prototype and executes it.

This lookup process is known as the prototype chain.

Shared Methods vs Instance Data

Every object created with the constructor has its own copy of the properties defined with this:

const u1 = new User("Neha", 3);
const u2 = new User("Arjun", 4);

console.log(u1.username); // "Neha"
console.log(u2.username); // "Arjun"

However, methods defined on the prototype are shared:

console.log(u1.describe === u2.describe); // true

This means the function exists once in memory and is reused by all instances. It’s both efficient and central to how JavaScript handles inheritance.

Forgetting new

A common mistake is calling a constructor function like a normal function:

function User(username) {
  this.username = username;
}

const result = User("Ravi"); // missing new

console.log(result); // undefined

In non-strict mode, this can even modify the global object:

console.log(window.username); // "Ravi"

This unintended side effect is one reason why modern JavaScript was introduced class syntax, which throws an error if you forget new.

Return Behavior Edge Case

Normally, constructors don’t explicitly return values. But if they do, JavaScript follows specific rules.

If a constructor returns a primitive, it is ignored:

function Sample() {
  this.score = 10;
  return 100;
}

const s = new Sample();
console.log(s.score); // 10

If it returns an object, that object replaces the newly created one:

function Custom() {
  this.score = 10;
  return { score: 999 };
}

const c = new Custom();
console.log(c.score); // 999

This behavior is rarely used in everyday code, but is important to understand for deeper JavaScript concepts.

new Behind the Scenes: Rebuilding It Manually

If you want a deeper understanding, the best way is to simulate what new actually does internally.

Here’s a custom implementation that mimics its behavior:

function createInstance(Constructor, ...params) {
  // Step 1: create a blank object
  const instance = {};

  // Step 2: attach prototype
  Object.setPrototypeOf(instance, Constructor.prototype);

  // Step 3: execute constructor with `this`
  const output = Constructor.apply(instance, params);

  // Step 4: decide what to return
  return output instanceof Object ? output : instance;
}

// Example usage
const user = createInstance(User, "Kiran", 28);

console.log(user.username); // "Kiran"
console.log(user.describe()); // "User Kiran is at level 28"

This isn’t just a theoretical exercise. Writing your own version forces you to understand each step instead of just memorizing it.

ES6 Classes: Same Engine, Cleaner Syntax

Modern JavaScript introduced class, but it didn’t change how things work underneath.

class User {
  constructor(username, level) {
    this.username = username;
    this.level = level;
  }

  describe() {
    return `User \({this.username} is at level \){this.level}`;
  }
}

const dev = new User("Sneha", 6);
console.log(dev.describe()); // "User Sneha is at level 6"

Even though this looks different, it still uses prototypes internally.

  • describe() is placed on User.prototype

  • Object creation still follows the same 4 steps

  • new and behaves the same

So classes are just a more structured way to write the same thing.

Important Points to Remember

  • new performs four actions:
    creates an object → connects prototype → runs constructor → returns object

  • Properties assigned using this belong to each instance separately

  • Functions added to .prototype are shared across all instances

  • Calling a constructor without new can lead to unexpected global assignments (in non-strict mode)

  • If a constructor returns an object manually, that object overrides the default return

  • Rewriting new yourself is one of the best ways to fully understand it