Skip to main content

Command Palette

Search for a command to run...

Understanding the new Keyword in JavaScript: Object Creation Under the Hood

Updated
6 min readView as Markdown
M

A developer who likes to builds on his ideas ..

Every time you write new SomeFunction(), JavaScript quietly does four things behind the scenes. This article pulls back the curtain — step by step, diagram by diagram.


What Does new Actually Do?

JavaScript is not a class-based language at its core. Beneath the class syntax sugar introduced in ES6 lies a prototype-based system where objects inherit directly from other objects. The new keyword is the bridge between constructor functions and object instances, and understanding it unlocks how JavaScript's inheritance model truly works.

When you invoke a function with new, JavaScript performs these four steps automatically:

  1. Creates a brand-new empty object {}

  2. Sets the prototype — links the new object's internal [[Prototype]] to the constructor's .prototype property

  3. Binds this — runs the constructor function with this pointing to the new object

  4. Returns the new object — unless the constructor explicitly returns a different object


Constructor Functions

A constructor function is a regular JavaScript function — with one convention: it is meant to be called with new, and its name starts with a capital letter (by community convention).

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

Without new, calling Person("Alice", 30) would run the function normally, and this would be the global object (sloppy mode) or undefined (strict mode).

With new, everything changes:

const alice = new Person("Alice", 30);

console.log(alice.name); // "Alice"
console.log(alice.age);  // 30

The Object Creation Process, Step by Step

Diagram — Constructor → Instance Creation Flow

Step 1 — A blank object is born

// JavaScript does this internally:
const obj = Object.create(Person.prototype);

Step 2 — The prototype chain is linked

The new object's [[Prototype]] slot is pointed at Person.prototype. This is what makes the object an instance of Person.

Object.getPrototypeOf(alice) === Person.prototype; // true
alice instanceof Person;                           // true

Step 3 — The constructor runs with this = new object

// Inside the constructor, this === obj (the new empty object)
this.name = "Alice"; // obj.name = "Alice"
this.age  = 30;      // obj.age  = 30

Step 4 — The object is returned

Unless Person explicitly returns another object, JavaScript returns this automatically. No return statement needed.

Edge case: If a constructor returns a primitive, JavaScript ignores it and still returns this. If it returns a plain object {}, that object is returned instead and your constructed instance is discarded.


Every function automatically gets a .prototype property. Methods added to it are shared across all instances — never copied.

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

Person.prototype.greet = function () {
  return `Hi, I'm \({this.name} and I'm \){this.age} years old.`;
};

const alice = new Person("Alice", 30);
const bob   = new Person("Bob",   25);

console.log(alice.greet()); // "Hi, I'm Alice and I'm 30 years old."
console.log(bob.greet());   // "Hi, I'm Bob and I'm 25 years old."

// Both instances share the SAME function — not copied
console.log(alice.greet === bob.greet); // true

When you call alice.greet(), JavaScript traverses the chain:

  1. Does alice own greet? No.

  2. Does Person.prototype own greet? Yes — found it.


Instances Created from Constructors

console.log(alice instanceof Person); // true
console.log(alice instanceof Object); // true (everything is!)
console.log(alice instanceof Array);  // false

Own properties vs. prototype properties

Property Belongs to hasOwnProperty
name, age The instance true
greet Person.prototype false
toString, hasOwnProperty Object.prototype false

Per-instance data lives on the instance; shared behaviour lives on the prototype.


Simulating new Yourself

function myNew(Constructor, ...args) {
  // Steps 1 & 2: create object and link prototype
  const obj = Object.create(Constructor.prototype);

  // Step 3: run the constructor with this = obj
  const result = Constructor.apply(obj, args);

  // Step 4: return the new object (or constructor's explicit object return)
  return result instanceof Object ? result : obj;
}

const charlie = myNew(Person, "Charlie", 28);
console.log(charlie.greet());           // "Hi, I'm Charlie and I'm 28 years old."
console.log(charlie instanceof Person); // true

new with ES6 Classes

ES6 class syntax is syntactic sugar — JavaScript compiles it to the same constructor + prototype pattern under the hood.

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    return `${this.name} makes a sound.`;
  }
}

const dog = new Animal("Rex");
console.log(dog.speak());           // "Rex makes a sound."
console.log(typeof Animal);         // "function" — still a function!
console.log(dog instanceof Animal); // true

The speak method lives on Animal.prototype, not on dog. The only practical difference from a plain constructor: calling a class without new throws a TypeError. Constructor functions have no such guard.


Common Mistakes

Forgetting new

const oops = Person("Dave", 40); // no new!
console.log(oops);        // undefined
console.log(window.name); // "Dave" — leaked to the global object

Replacing the prototype after creating instances

Person.prototype = { greet() { return "hello"; } }; // replaces the object!
alice.greet(); // TypeError — alice still points to the OLD prototype

Arrow functions can't be constructors

const Broken = (name) => { this.name = name; };
new Broken("x"); // TypeError: Broken is not a constructor

Quick Reference

// 1. Define a constructor
function Car(make, model) {
  this.make  = make;
  this.model = model;
}

// 2. Add shared methods
Car.prototype.describe = function () {
  return `\({this.make} \){this.model}`;
};

// 3. Create instances
const car1 = new Car("Toyota", "Camry");
const car2 = new Car("Honda",  "Civic");

// 4. Verify prototype links
Object.getPrototypeOf(car1) === Car.prototype; // true
car1.describe === car2.describe;               // true — shared!
car1.hasOwnProperty("make");                   // true  — own property
car1.hasOwnProperty("describe");               // false — inherited

Key Takeaways

  • new runs four implicit steps: create object → link prototype → bind this → return object

  • Methods on Constructor.prototype are shared across all instances, not copied

  • The prototype chain is a live lookup, not a data copy

  • ES6 class compiles to the same constructor + prototype pattern

  • instanceof walks the prototype chain — it does not check a type tag

  • Arrow functions cannot be constructors


If this article helped you, share it with someone learning JavaScript internals. Prototype chains are one of those concepts that suddenly make everything click.

1 views