The new Keyword in JavaScript: How Objects Are Created

Who is this for? If you have seen
newin JavaScript code and wondered what it actually does behind the scenes — or if you want to understand how objects are built from constructor functions — this guide explains everything step by step.
Table of Contents
Introduction
When you need multiple objects with the same structure — say, ten users, each with a name, email, and role — you could write each one by hand:
const user1 = { name: "Priya", email: "priya@example.com", role: "admin" };
const user2 = { name: "Rahul", email: "rahul@example.com", role: "member" };
const user3 = { name: "Ananya", email: "ananya@example.com", role: "member" };
// ... and seven more
This works, but it is repetitive, hard to maintain, and there is no connection between these objects — no shared behaviour, no common blueprint.
JavaScript gives you a better way: constructor functions and the new keyword. You define the shape of an object once, and then use new to stamp out as many instances as you need.
💡 Open your browser console (
F12→ Console tab) and try every example as you read.
1. What Does the new Keyword Do?
new is a special keyword that, when placed in front of a function call, transforms that function into an object factory. It handles the repetitive setup work — creating an empty object, linking it, and returning it — automatically.
Without new, a function just runs and returns whatever it explicitly returns (or undefined). With new, four things happen automatically:
1. A brand new empty object is created
2. `this` inside the function is set to that new object
3. The new object's prototype is linked to the constructor's prototype
4. The new object is automatically returned
The difference in one example
function greet() {
console.log("Hello!");
}
// Without new — just calls the function normally
greet(); // "Hello!"
// With new — creates and returns a new object
const result = new greet();
console.log(result); // greet {} ← an empty object was created and returned
This does not look useful yet — because greet was not designed to be a constructor. Let us look at functions that are.
2. Constructor Functions
A constructor function is a regular function written with the intent to be called with new. By convention, constructor functions are named with a capital first letter — User, Car, Product — to signal to other developers: "call this with new."
Inside a constructor function, you use this to attach properties to the object being created.
Your first constructor function
function User(name, email, role) {
this.name = name;
this.email = email;
this.role = role;
}
There is no return statement. There is no manual object creation. You just describe what properties the new object should have, using this as a reference to the object being built.
Creating objects with new
const user1 = new User("Priya", "priya@example.com", "admin");
const user2 = new User("Rahul", "rahul@example.com", "member");
const user3 = new User("Ananya", "ananya@example.com", "member");
console.log(user1);
// User { name: 'Priya', email: 'priya@example.com', role: 'admin' }
console.log(user2.name); // "Rahul"
console.log(user3.email); // "ananya@example.com"
Each call to new User(...) produces a completely separate object, but they all share the same structure defined by the constructor.
Adding methods to a constructor
You can add methods — functions as properties — directly inside the constructor:
function Car(brand, model, year) {
this.brand = brand;
this.model = model;
this.year = year;
this.describe = function() {
return this.year + " " + this.brand + " " + this.model;
};
}
const car1 = new Car("Toyota", "Fortuner", 2022);
const car2 = new Car("Honda", "City", 2020);
console.log(car1.describe()); // "2022 Toyota Fortuner"
console.log(car2.describe()); // "2020 Honda City"
⚠️ A note on methods in constructors: Putting methods directly inside the constructor means each new object gets its own copy of that function — which wastes memory if you create many instances. The better approach is to add methods to the prototype (covered in section 4).
What happens if you call a constructor without new?
function User(name, email) {
this.name = name;
this.email = email;
}
// ❌ Without new — this refers to the global object (or undefined in strict mode)
const user = User("Priya", "priya@example.com");
console.log(user); // undefined — nothing was returned
console.log(window.name); // "Priya" — accidentally set on the global object!
This is one of the most common beginner mistakes. Always use new when calling a constructor function. The capital letter naming convention is there precisely to remind you.
3. The Object Creation Process
When you write new User("Priya", "priya@example.com", "admin"), here is exactly what JavaScript does — step by step:
Step 1 — A new empty object is created
// JavaScript secretly does this first:
const obj = {};
A plain, empty object with no properties is created in memory.
Step 2 — this is pointed at the new object
// JavaScript sets:
this = obj; // now `this` inside the constructor refers to this new object
Every time you write this.name = name inside the constructor, you are writing a property onto this new object.
Step 3 — The constructor function body runs
function User(name, email, role) {
this.name = name; // obj.name = "Priya"
this.email = email; // obj.email = "priya@example.com"
this.role = role; // obj.role = "admin"
}
The constructor runs line by line, attaching each property to the object via this.
Step 4 — The new object is automatically returned
// JavaScript secretly does this last:
return this; // returns the fully built object
You do not write return — new handles it. The fully populated object is returned and assigned to your variable.
Visualising all four steps together
new User("Priya", "priya@example.com", "admin")
Step 1: {} ← empty object created
Step 2: this → {} ← this points to it
Step 3: this.name = "Priya"
this.email = "priya@example.com"
this.role = "admin"
→ { name: "Priya", email: "priya@example.com", role: "admin" }
Step 4: return this ← object returned automatically
Result: user1 = { name: "Priya", email: "priya@example.com", role: "admin" }
What if you add your own return to a constructor?
function User(name) {
this.name = name;
return { message: "I overrode the return!" }; // returning an object
}
const user = new User("Priya");
console.log(user); // { message: "I overrode the return!" }
// The name property is lost — your return replaced the automatic one
If a constructor explicitly returns an object, that object replaces the automatic return. If it returns a primitive (number, string, boolean), the return is ignored and the constructed object is used as normal. In practice, you should never add a return to a constructor function.
4. How new Links Prototypes
This is the most important — and most misunderstood — part of what new does.
What is a prototype?
Every function in JavaScript has a special property called prototype. It is just an object. When you create instances with new, those instances are linked to this prototype object.
This link lets all instances share methods and properties without each one having its own copy — which saves memory and keeps your code DRY.
function User(name, email) {
this.name = name;
this.email = email;
}
// Instead of putting greet inside the constructor,
// add it to the prototype — all instances will share it
User.prototype.greet = function() {
return "Hi, I am " + this.name + "!";
};
User.prototype.getEmail = function() {
return "Contact me at: " + this.email;
};
Now every User instance automatically has access to greet and getEmail:
const user1 = new User("Priya", "priya@example.com");
const user2 = new User("Rahul", "rahul@example.com");
console.log(user1.greet()); // "Hi, I am Priya!"
console.log(user2.greet()); // "Hi, I am Rahul!"
console.log(user1.getEmail()); // "Contact me at: priya@example.com"
Neither user1 nor user2 has a greet property of their own. When you call user1.greet(), JavaScript looks for greet on user1, does not find it, then looks up the prototype chain and finds it on User.prototype. This lookup is automatic.
The prototype link — what new wires up
const user1 = new User("Priya", "priya@example.com");
// new does this automatically:
// user1.__proto__ === User.prototype → true
console.log(Object.getPrototypeOf(user1) === User.prototype); // true
Every instance created with new User() has an internal link — [[Prototype]] — pointing to User.prototype. This is what allows shared methods to work.
Methods on prototype vs methods on the instance
function Car(brand) {
this.brand = brand;
// BAD — each instance gets its own copy of this function
this.honk = function() { return this.brand + " goes beep!"; };
}
// GOOD — one copy shared by all instances via prototype
Car.prototype.honk = function() {
return this.brand + " goes beep!";
};
const car1 = new Car("Toyota");
const car2 = new Car("Honda");
// With prototype approach:
console.log(car1.honk === car2.honk); // true — they share the same function
// With constructor approach:
// car1.honk === car2.honk would be false — different copies
With 1000 Car instances, the prototype approach stores honk once. The constructor approach stores 1000 copies. The prototype is always the right choice for methods.
5. Instances Created from Constructors
An instance is any object created using new with a specific constructor. Each instance:
Has its own unique property values (name, email, etc.)
Shares methods from the constructor's prototype
Knows which constructor created it (via
instanceof)
Checking if an object is an instance
function User(name) { this.name = name; }
function Car(brand) { this.brand = brand; }
const user1 = new User("Priya");
const car1 = new Car("Toyota");
console.log(user1 instanceof User); // true
console.log(user1 instanceof Car); // false
console.log(car1 instanceof Car); // true
console.log(car1 instanceof User); // false
instanceof checks the prototype chain to determine which constructor was responsible for creating an object.
Each instance is independent
function Counter(start) {
this.count = start;
this.increment = function() {
this.count++;
};
}
const counterA = new Counter(0);
const counterB = new Counter(100);
counterA.increment();
counterA.increment();
counterA.increment();
counterB.increment();
console.log(counterA.count); // 3 ← independent
console.log(counterB.count); // 101 ← independent
Changing one instance never affects another. Each object has its own copy of count.
A complete example — putting it all together
function Product(name, price, inStock) {
this.name = name;
this.price = price;
this.inStock = inStock;
}
// Shared methods on the prototype
Product.prototype.getDetails = function() {
return this.name + " — ₹" + this.price;
};
Product.prototype.checkAvailability = function() {
if (this.inStock) {
return this.name + " is available.";
} else {
return this.name + " is out of stock.";
}
};
// Creating instances
const laptop = new Product("Laptop", 75000, true);
const phone = new Product("Phone", 25000, false);
const tablet = new Product("Tablet", 40000, true);
// Each instance uses its own properties
console.log(laptop.getDetails()); // "Laptop — ₹75000"
console.log(phone.getDetails()); // "Phone — ₹25000"
console.log(laptop.checkAvailability()); // "Laptop is available."
console.log(phone.checkAvailability()); // "Phone is out of stock."
// Checking instances
console.log(tablet instanceof Product); // true
console.log(Object.getPrototypeOf(laptop) === Product.prototype); // true
Verifying the four-step process on a real object
function Animal(name, sound) {
this.name = name;
this.sound = sound;
}
Animal.prototype.speak = function() {
return this.name + " says " + this.sound + "!";
};
const dog = new Animal("Dog", "Woof");
const cat = new Animal("Cat", "Meow");
// Own properties (set by constructor)
console.log(dog.hasOwnProperty("name")); // true
console.log(dog.hasOwnProperty("sound")); // true
// Prototype method (NOT owned by the instance)
console.log(dog.hasOwnProperty("speak")); // false ← lives on prototype
// But the method still works via the prototype chain
console.log(dog.speak()); // "Dog says Woof!"
console.log(cat.speak()); // "Cat says Meow!"
Diagrams
Constructor → Instance Creation Flow
┌─────────────────────────────────────────────────────────────┐
│ CONSTRUCTOR → INSTANCE CREATION FLOW │
│ │
│ function User(name, email) { │
│ this.name = name; │
│ this.email = email; │
│ } │
│ │
│ new User("Priya", "priya@example.com") │
│ │ │
│ ┌───────────────┴───────────────────┐ │
│ │ 4-STEP PROCESS │ │
│ │ │ │
│ Step 1 │ {} ← create empty object │ │
│ │ ↓ │ │
│ Step 2 │ this → {} ← link this to it │ │
│ │ ↓ │ │
│ Step 3 │ this.name = "Priya" │ │
│ │ this.email = "priya@example.com" │ │
│ │ ↓ │ │
│ Step 4 │ return this ← auto return │ │
│ └───────────────┬───────────────────┘ │
│ ↓ │
│ user1 = { name: "Priya", email: "priya@example.com" } │
│ │
│ Call again → completely new, independent object │
│ new User("Rahul", "rahul@example.com") │
│ → user2 = { name: "Rahul", email: "rahul@example.com" } │
└─────────────────────────────────────────────────────────────┘
Prototype Linking Visual
┌─────────────────────────────────────────────────────────────┐
│ PROTOTYPE LINKING VISUAL │
│ │
│ function User(name) { this.name = name; } │
│ User.prototype.greet = function() { ... }; │
│ │
│ ┌─────────────────┐ │
│ │ User.prototype │ │
│ │ ───────────── │ │
│ │ greet: fn() │ │
│ │ getEmail: fn() │ │
│ └────────┬────────┘ │
│ │ [[Prototype]] link │
│ ┌────────────┴────────────┐ │
│ ↓ ↓ │
│ ┌─────────────────┐ ┌─────────────────┐ │
│ │ user1 │ │ user2 │ │
│ │ ───────────── │ │ ───────────── │ │
│ │ name: "Priya" │ │ name: "Rahul" │ │
│ │ email: "p@..." │ │ email: "r@..." │ │
│ └─────────────────┘ └─────────────────┘ │
│ │
│ user1.greet() → not found on user1 │
│ → look up to User.prototype │
│ → found! greet() runs with this = user1 │
│ │
│ ✦ Own properties live on each instance (name, email) │
│ ✦ Shared methods live on the prototype (greet, getEmail) │
│ ✦ One copy of each method, shared by all instances │
│ ✦ instanceof checks this prototype link │
└─────────────────────────────────────────────────────────────┘
Quick Reference
// ─── Define a constructor ─────────────────────────────────
function Person(name, age) {
this.name = name; // own property — unique per instance
this.age = age; // own property — unique per instance
}
// ─── Add shared methods via prototype ─────────────────────
Person.prototype.greet = function() {
return "Hi, I am " + this.name;
};
Person.prototype.isAdult = function() {
return this.age >= 18;
};
// ─── Create instances ─────────────────────────────────────
const p1 = new Person("Priya", 25);
const p2 = new Person("Rahul", 16);
// ─── Access own properties ────────────────────────────────
console.log(p1.name); // "Priya"
console.log(p2.age); // 16
// ─── Access prototype methods ─────────────────────────────
console.log(p1.greet()); // "Hi, I am Priya"
console.log(p2.isAdult()); // false
// ─── Check instance relationship ──────────────────────────
console.log(p1 instanceof Person); // true
console.log(Object.getPrototypeOf(p1) === Person.prototype); // true
// ─── Own vs prototype property ────────────────────────────
console.log(p1.hasOwnProperty("name")); // true ← own
console.log(p1.hasOwnProperty("greet")); // false ← on prototype
Wrapping Up
The new keyword is one of the most important concepts in JavaScript object-oriented programming. Here is everything you learned:
newtransforms a regular function into an object factory — running four automatic stepsConstructor functions use
thisto describe what properties each new object should have — no explicitreturnneededThe four steps of
new: create empty object → linkthis→ run constructor body → auto returnnewlinks the new object's prototype to the constructor's.prototype— enabling shared methods across all instancesInstances are independent objects — each with its own properties, but sharing prototype methods
Use
instanceofto check which constructor created an objectAlways put methods on the prototype, not inside the constructor — one shared copy is better than one per instance
Once you understand this, JavaScript's class syntax (introduced in ES6) will look very familiar — it is simply a cleaner way to write exactly what you learned here, built on the same constructor and prototype mechanism under the hood.
Happy coding! 🚀
Next step: Look into ES6 class syntax — it uses the same new keyword and prototype system you just learned, just with cleaner, more readable syntax.
