DEV Community

Cover image for The new Keyword in JavaScript
SATYA SOOTAR
SATYA SOOTAR

Posted on

The new Keyword in JavaScript

Hello readers đź‘‹, welcome to the 15th blog in this JavaScript series!

Today, let’s talk about something that sits right at the core of object-oriented patterns in JavaScript: the new keyword. You’ve probably used it with constructor functions or classes countless times, but have you ever stopped to wonder what exactly it does behind the scenes?

The new keyword can feel like magic at first, but once you break it down, it’s just a sequence of well-defined steps that create objects and connect them to prototypes. Let’s unpack it in a way that makes complete sense.

What does the new keyword do?

In simple terms, new takes a regular function, turns it into a constructor call, and gives you back a fresh object with its prototype properly linked. When you write something like:

const person = new Person("Satya", 25);
Enter fullscreen mode Exit fullscreen mode

JavaScript does a bunch of things automatically:

  1. Creates a brand new empty object.
  2. Links that object’s internal [[Prototype]] to the constructor’s prototype property.
  3. Calls the constructor function with this pointing to the newly created object.
  4. If the constructor doesn’t explicitly return an object, it returns the newly created object by default.

These four steps form the backbone of how new operates. The rest of this blog will explore each one in detail and show how they come together.

Constructor functions

A constructor function is nothing special. It’s just a regular JavaScript function meant to be called with new. What sets it apart is that we capitalize the first letter (by convention) and use this inside to set properties on the instance that will be created.

Here’s a simple constructor:

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Enter fullscreen mode Exit fullscreen mode

When you call new Person("Satya", 25), you get back an object with name and age properties. But if you forget new and call it like a normal function, this inside it will point to the global object (in non-strict mode) or be undefined (in strict mode). That’s a common source of bugs, and it’s exactly why new exists, to ensure that this refers to the fresh object and that the prototype wiring happens correctly.

The object creation process step by step

To really understand new, let’s recreate its behavior manually. I’ve written a small utility function that mimics what new does under the hood:

function myNew(constructor, ...args) {
  // Step 1: Create a new empty object
  const obj = {};

  // Step 2: Link the new object's prototype to the constructor's prototype
  Object.setPrototypeOf(obj, constructor.prototype);

  // Step 3: Call the constructor with 'this' set to the new object
  const result = constructor.apply(obj, args);

  // Step 4: If the constructor returns an object, use that; otherwise, return the new object
  return result instanceof Object ? result : obj;
}
Enter fullscreen mode Exit fullscreen mode

Now, if you use myNew(Person, "Satya", 25), you get the same result as new Person("Satya", 25). Let’s walk through the steps:

  • Step 1: A plain, empty object is born. It has no properties yet.
  • Step 2: That object’s hidden [[Prototype]] property is set to Person.prototype. This is what makes instanceof and prototype methods work.
  • Step 3: The constructor runs with its this pointing to the newly created object. Any properties added to this inside the constructor become own properties of the instance.
  • Step 4: By default, the new object is returned. However, if the constructor explicitly returns another object, that returned object overrides the automatically created one. This is a subtle edge case we’ll touch on later.

This step-by-step view strips away the mystery and shows that new is really just a convenience mechanism for object creation and prototype linkage.

How new links prototypes

Prototypes are how JavaScript shares behaviour among instances. When you set something on Person.prototype, all instances created with new Person() get access to it through the prototype chain. The new keyword handles the linkage automatically.

Here’s an example:

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

Person.prototype.sayHello = function () {
  console.log("Hi, I am " + this.name);
};

const p = new Person("Satya");
p.sayHello(); // Hi, I am Satya

console.log(Object.getPrototypeOf(p) === Person.prototype); // true
Enter fullscreen mode Exit fullscreen mode

The moment new Person("Satya") runs, JavaScript connects p.__proto__ (or more accurately, the internal slot behind Object.getPrototypeOf(p)) to Person.prototype. That’s why p.sayHello works even though sayHello isn’t directly on p. The engine finds it by walking up the prototype chain.

A nice thing about this is that all instances share the same prototype methods. There’s only one copy of sayHello in memory, not one per instance. That’s a big win for performance and maintainability.

Instances created from constructors

Every time you use new, you create a distinct instance with its own set of properties. The constructor sets up the “own” data, while the prototype provides shared behaviour.

function Animal(type) {
  this.type = type;
}

Animal.prototype.describe = function () {
  console.log("This is a " + this.type);
};

const dog = new Animal("dog");
const cat = new Animal("cat");

dog.describe(); // This is a dog
cat.describe(); // This is a cat

console.log(dog.describe === cat.describe); // true
Enter fullscreen mode Exit fullscreen mode

Both dog and cat have their own type property, but they share the exact same describe method through the prototype. Even if you add a new method to Animal.prototype after creating instances, they will immediately see the update, because the chain is live.

Understanding this relationship between constructor, instance, and prototype is the key to really getting JavaScript’s object model.

Visualizing the flow (diagram ideas)

Sometimes a picture is worth a thousand words, but let me describe the flow that a single new call triggers. Imagine a simple visual:

  • You have the constructor function Person.
  • new Person("Satya") is called.
  • An empty object {} is created.
  • An arrow links that object’s [[Prototype]] to Person.prototype.
  • The constructor runs with this = {} and adds name: "Satya".
  • The finished object is returned.

A common pitfall: returning objects from constructors

Most constructors don’t have a return statement, and they simply let new do its default behaviour. But if a constructor explicitly returns an object, the automatic instance is discarded in favour of that returned object.

function Something() {
  this.value = 10;
  return { override: true };
}

const result = new Something();
console.log(result); // { override: true }
console.log(result instanceof Something); // false
Enter fullscreen mode Exit fullscreen mode

This rarely happens in practice, but it’s good to know. A constructor that returns a primitive value (string, number, etc.) doesn’t break the new behaviour—the default object is still returned. Only an object return overrides it.

Why understanding new matters

Even though modern JavaScript has the class syntax, classes are just syntactic sugar over constructor functions and prototypes. Under the hood, new works exactly the same way. If you ever peek at transpiled code or need to debug prototype issues, knowing how new operates will help you reason about what’s happening.

It also helps you understand design patterns like factory functions and why some codebases avoid new altogether. When you know both sides, you can make better decisions.

Conclusion

Let’s quickly recap what we explored:

  • The new keyword automates object creation, prototype linking, this binding, and returning the instance.
  • Constructor functions are regular functions meant to be invoked with new.
  • The process is: create empty object, link prototype, call constructor with this, return the object (unless an object is explicitly returned).
  • new links the instance’s prototype to the constructor’s prototype, enabling shared methods.
  • Each instance gets its own data, but methods come from the prototype, saving memory.
  • Understanding this mechanism demystifies a lot of JavaScript’s object model, including the class syntax.

Once you truly grasp what new does under the hood, a lot of JavaScript’s object-oriented behaviour becomes predictable and even elegant.


Hope you found this helpful! If you spot any mistakes or have suggestions, let me know. You can find me on LinkedIn and X, where I post more about web development.

Top comments (0)