The new Keyword in JavaScript
The Magic of 'new': JavaScript's Object Factory π
Turning chai into code and ideas into full-stack applications. Sharing lessons from my development journey, one commit at a time.
The Cookie Cutter Moment πͺ
Last Diwali, my little cousin asked me to help make cookies. She handed me a star-shaped cookie cutter and said, "Make a hundred of these."
I pressed the cutter into the dough. Star cookie #1.
I pressed again. Star cookie #2.
Again. Star cookie #3.
Each cookie was unique (slightly different sizes, imperfect edges), but they all came from the same blueprintβthe cookie cutter.
As I made cookie #47, it hit me: This is exactly what the new keyword does in JavaScript.
Cookie cutter = Constructor function
Dough = Memory
Pressing the cutter = Using
newEach cookie = An object instance
That moment, covered in flour, I finally understood object-oriented programming.
What Does new Actually Do? π€
The new keyword is JavaScript's way of creating object instances from a blueprint. Here's the simple version:
// Constructor function (the blueprint)
function Cookie(shape, flavor) {
this.shape = shape;
this.flavor = flavor;
}
// Using 'new' to create instances
const cookie1 = new Cookie("star", "chocolate");
const cookie2 = new Cookie("heart", "vanilla");
console.log(cookie1); // Cookie { shape: 'star', flavor: 'chocolate' }
console.log(cookie2); // Cookie { shape: 'heart', flavor: 'vanilla' }
Each cookie is a separate object, but both were created using the same blueprint.
Without new: The Confusion π«
What happens if you forget new? Let me show you the chaos:
function Cookie(shape, flavor) {
this.shape = shape;
this.flavor = flavor;
}
// WITHOUT 'new'
const cookie = Cookie("star", "chocolate");
console.log(cookie); // undefined
console.log(window.shape); // "star" π± (global variable!)
console.log(window.flavor); // "chocolate" π± (global variable!)
What just happened?!
When you call Cookie() without new:
thisrefers to the global object (window in browsers)The function returns
undefined(no explicit return)You just polluted the global scope! π
With new:
// WITH 'new'
const cookie = new Cookie("star", "chocolate");
console.log(cookie); // Cookie { shape: 'star', flavor: 'chocolate' }
console.log(window.shape); // undefined (safe!)
The 4 Steps of new: Behind the Magic π©
When you use new, JavaScript does four things automatically:
function Cookie(shape, flavor) {
// STEP 1: Create a new empty object
// (JavaScript does: const this = {};)
// STEP 2: Set the prototype
// (JavaScript does: this.__proto__ = Cookie.prototype;)
// STEP 3: Execute the constructor function
this.shape = shape;
this.flavor = flavor;
// STEP 4: Return the new object
// (JavaScript does: return this;)
}
const cookie = new Cookie("star", "chocolate");
Let's break down each step:
Step 1: Create Empty Object
// What JavaScript does internally:
const this = {};
A brand new empty object is created in memory.
Step 2: Link Prototype
// What JavaScript does internally:
this.__proto__ = Cookie.prototype;
The new object's internal prototype is linked to the constructor's prototype. This enables inheritance! (More on this later.)
Step 3: Execute Constructor
// Your code runs:
this.shape = shape; // Adds properties
this.flavor = flavor; // Adds properties
The constructor function body executes, and this refers to the new object.
Step 4: Return Object
// What JavaScript does internally:
return this;
The newly created object is returned automatically.
Visual Representation:
new Cookie("star", "chocolate")
β
ββ Step 1: Create empty object β {}
β
ββ Step 2: Link prototype β {__proto__: Cookie.prototype}
β
ββ Step 3: Add properties β {shape: "star", flavor: "chocolate"}
β
ββ Step 4: Return object β Cookie {shape: "star", flavor: "chocolate"}
Constructor Functions: The Blueprint Pattern π
A constructor function is just a regular function used with new. Naming convention: PascalCase (capitalize first letter).
// Constructor function
function User(name, email) {
this.name = name;
this.email = email;
this.isActive = true; // Default value
}
// Create instances
const user1 = new User("Alice", "alice@example.com");
const user2 = new User("Bob", "bob@example.com");
console.log(user1.name); // "Alice"
console.log(user2.name); // "Bob"
console.log(user1.isActive); // true
console.log(user1 === user2); // false (different objects!)
Adding Methods to Instances
function User(name, email) {
this.name = name;
this.email = email;
// BAD: Creates a new function for EACH instance
this.greet = function() {
console.log(`Hi, I'm ${this.name}`);
};
}
const user1 = new User("Alice", "alice@example.com");
const user2 = new User("Bob", "bob@example.com");
console.log(user1.greet === user2.greet); // false π±
// Each user has their OWN copy of greet function!
// Memory waste if you create 1000 users!
Solution: Use prototypes (next section).
Prototypes: Shared Methods π
Every function in JavaScript has a .prototype property. Objects created with new inherit from this prototype.
function User(name, email) {
this.name = name;
this.email = email;
}
// GOOD: Add methods to the prototype
User.prototype.greet = function() {
console.log(`Hi, I'm ${this.name}`);
};
User.prototype.changeEmail = function(newEmail) {
this.email = newEmail;
console.log(`Email updated to ${this.email}`);
};
// Create instances
const user1 = new User("Alice", "alice@example.com");
const user2 = new User("Bob", "bob@example.com");
console.log(user1.greet === user2.greet); // true
// Both users share the SAME function in memory!
user1.greet(); // "Hi, I'm Alice"
user2.greet(); // "Hi, I'm Bob"
Why this works:
user1
ββ name: "Alice"
ββ email: "alice@example.com"
ββ __proto__ β User.prototype
ββ greet: function()
ββ changeEmail: function()
user2
ββ name: "Bob"
ββ email: "bob@example.com"
ββ __proto__ β User.prototype (SAME OBJECT!)
Real-World Examples π
Example 1: Building a Car Factory
function Car(make, model, year) {
this.make = make;
this.model = model;
this.year = year;
this.mileage = 0;
}
Car.prototype.drive = function(miles) {
this.mileage += miles;
console.log(`Drove \({miles} miles. Total: \){this.mileage}`);
};
Car.prototype.getInfo = function() {
return `\({this.year} \){this.make} ${this.model}`;
};
// Create cars
const car1 = new Car("Toyota", "Camry", 2020);
const car2 = new Car("Honda", "Civic", 2021);
car1.drive(100); // "Drove 100 miles. Total: 100"
car1.drive(50); // "Drove 50 miles. Total: 150"
console.log(car1.getInfo()); // "2020 Toyota Camry"
console.log(car2.getInfo()); // "2021 Honda Civic"
Example 2: Todo List Items
function TodoItem(text) {
this.text = text;
this.completed = false;
this.createdAt = new Date();
}
TodoItem.prototype.toggle = function() {
this.completed = !this.completed;
console.log(`"\({this.text}" is now \){this.completed ? 'completed' : 'incomplete'}`);
};
TodoItem.prototype.edit = function(newText) {
this.text = newText;
console.log(`Updated to: "${this.text}"`);
};
// Usage
const todo1 = new TodoItem("Learn JavaScript");
const todo2 = new TodoItem("Build a project");
todo1.toggle(); // "Learn JavaScript" is now completed
todo2.edit("Build an awesome project"); // Updated to: "Build an awesome project"
Example 3: Bank Account System
function BankAccount(owner, initialBalance) {
this.owner = owner;
this.balance = initialBalance;
this.transactions = [];
}
BankAccount.prototype.deposit = function(amount) {
this.balance += amount;
this.transactions.push({ type: 'deposit', amount, date: new Date() });
console.log(`Deposited $${amount}. New balance: $${this.balance}`);
};
BankAccount.prototype.withdraw = function(amount) {
if (amount > this.balance) {
console.log("Insufficient funds!");
return;
}
this.balance -= amount;
this.transactions.push({ type: 'withdraw', amount, date: new Date() });
console.log(`Withdrew $${amount}. New balance: $${this.balance}`);
};
BankAccount.prototype.getStatement = function() {
console.log(`Account Owner: ${this.owner}`);
console.log(`Balance: $${this.balance}`);
console.log("Recent transactions:");
this.transactions.forEach(t => {
console.log(` ${t.type}: $${t.amount}`);
});
};
// Usage
const account = new BankAccount("Alice", 1000);
account.deposit(500); // Deposited \(500. New balance: \)1500
account.withdraw(200); // Withdrew \(200. New balance: \)1300
account.getStatement();
Modern Alternative: ES6 Classes π
In 2015, JavaScript introduced class syntax (syntactic sugar over constructor functions):
// Old way (Constructor Function)
function User(name, email) {
this.name = name;
this.email = email;
}
User.prototype.greet = function() {
console.log(`Hi, I'm ${this.name}`);
};
// New way (ES6 Class)
class User {
constructor(name, email) {
this.name = name;
this.email = email;
}
greet() {
console.log(`Hi, I'm ${this.name}`);
}
}
// Both create the same thing!
const user1 = new User("Alice", "alice@example.com");
user1.greet(); // "Hi, I'm Alice"
Under the hood, classes are just constructor functions! JavaScript converts class syntax to the function pattern.
Proof:
class User {
constructor(name) {
this.name = name;
}
}
console.log(typeof User); // "function" π€―
Common Gotchas & Solutions π¨
Gotcha 1: Forgetting new
function User(name) {
this.name = name;
}
const user = User("Alice"); // Forgot 'new'
console.log(user); // undefined
console.log(window.name); // "Alice" (global pollution!)
Solution: Always use new, or use ES6 classes (they enforce it).
Gotcha 2: Returning Values
function User(name) {
this.name = name;
// Returning a primitive (ignored!)
return 42;
}
const user1 = new User("Alice");
console.log(user1); // User { name: 'Alice' } (return ignored)
function User2(name) {
this.name = name;
// Returning an object (overrides!)
return { customProp: "I'm different" };
}
const user2 = new User2("Bob");
console.log(user2); // { customProp: "I'm different" } π€―
Rule:
Returning primitives (numbers, strings) β ignored
Returning objects β overrides the default return
Gotcha 3: Arrow Functions as Constructors
// Arrow functions CAN'T be constructors!
const User = (name) => {
this.name = name;
};
const user = new User("Alice"); // TypeError: User is not a constructor
Why? Arrow functions don't have their own this binding. Use regular functions or classes.
Interview Questions πΌ
Q: What does the new keyword do?
Strong Answer: "The new keyword creates a new instance from a constructor function. It does four things: creates an empty object, sets the object's prototype to the constructor's prototype, executes the constructor with this bound to the new object, and returns the new object. This enables object-oriented programming in JavaScript."
Q: What's the difference between a regular function call and using new?
Strong Answer: "Without new, the function executes normally and this refers to the global object. With new, JavaScript creates a new object, binds this to that object, links its prototype, and returns the object. Forgetting new can cause bugs by polluting the global scope."
Q: What's the purpose of the prototype?
Strong Answer: "The prototype allows multiple instances to share methods, saving memory. Instead of each instance having its own copy of a method, they all reference the same function on the prototype. This implements inheritanceβinstances inherit properties and methods from their constructor's prototype."
Practice Challenge ποΈ
Build a simple Product constructor with:
Properties: name, price, quantity
Methods:
restock(amount),sell(amount),getTotal()
Solution:
function Product(name, price, quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
Product.prototype.restock = function(amount) {
this.quantity += amount;
console.log(`Restocked \({amount} units. Total: \){this.quantity}`);
};
Product.prototype.sell = function(amount) {
if (amount > this.quantity) {
console.log("Not enough stock!");
return;
}
this.quantity -= amount;
console.log(`Sold \({amount} units. Remaining: \){this.quantity}`);
};
Product.prototype.getTotal = function() {
return this.price * this.quantity;
};
// Usage
const laptop = new Product("Laptop", 999, 10);
laptop.sell(3); // Sold 3 units. Remaining: 7
laptop.restock(5); // Restocked 5 units. Total: 12
console.log(laptop.getTotal()); // 11988
The Cookie Jar Wisdom πͺ
By the time I finished making those hundred cookies, each one slightly different but all from the same cutter, I realized something profound:
Programming is about creating systems, not individual solutions.
The new keyword isn't just about making objectsβit's about scaling patterns. One blueprint, infinite possibilities.
Just like my cookie cutter could make stars, hearts, or trees, a constructor function can create users, products, tasks, or anything you need. The pattern stays the same; the instances are unique.
Every time you use new, you're telling JavaScript: "Take this blueprint and build me something."
And JavaScript, like a loyal assistant, creates exactly what you asked for.
What's Next?
You now understand:
Constructor functions
The
newkeyword's four stepsPrototypes and inheritance
ES6 class syntax (modern alternative)
Next topics to explore:
classsyntax in depthextendsand inheritancesuperkeywordPrivate fields and methods