The Problem Objects Solve
Imagine you need to store information about a person. Without objects, you'd need separate, disconnected variables:
let personName = "Alice";
let personAge = 30;
let personCity = "Lagos";
let personJob = "Engineer";
let personSalary = 150000;This is messy. If you have 100 people, you'd have 500 variables · all with no clear connection to each other. What if you need to pass "Alice" to a function? You'd have to pass 5 separate variables every time.
With an object, all of Alice's data lives together in one neat container:
let person = {
name: "Alice",
age: 30,
city: "Lagos",
job: "Engineer",
salary: 150000
};Now everything about Alice travels together, is organized, and is easy to access.
What Is an Object?
A JavaScript object is a collection of named values called properties. Each property has a key (name) and a value. Together, a key-value pair is called a property.
Think of an object like a form or a profile card:
┌─────────────────────────────┐
│ PROFILE CARD │
├──────────────┬──────────────┤
│ name │ "Alice" │ ← property (key: value)
│ age │ 30 │ ← property
│ city │ "Lagos" │ ← property
│ job │ "Engineer" │ ← property
└──────────────┴──────────────┘Why Objects Are Central to Everything
Objects are the most important concept in JavaScript. Almost everything in JavaScript is either an object or behaves like one:
- Strings have properties and methods:
"Hello".length,"Hello".toUpperCase() - Arrays are objects:
[1,2,3].push(4) - Functions are objects:
myFunc.name,myFunc.length - The browser window is an object:
window.alert(),window.location - HTML elements are objects:
document.getElementById("btn").innerHTML - Dates are objects:
new Date().getFullYear() - JSON data from APIs is made of objects
In real jobs · web development, backend APIs, mobile apps, data science · you will work with objects every single day. They are the primary way to model real-world entities in code.
Real-World Analogies
| Real World | JavaScript Object |
|---|---|
| A student's record file | { name: "Kemi", grade: "A", score: 95 } |
| A product on a shelf | { name: "Laptop", price: 250000, stock: 15 } |
| A car | { brand: "Toyota", model: "Camry", year: 2022, color: "Black" } |
| A bank account | { owner: "Emeka", balance: 500000, type: "Savings" } |
The Object Literal · The Most Common Way
An object literal is the simplest and most direct way to create an object. You write the object directly in your code between curly braces { }, with properties separated by commas:
let person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};Syntax breakdown:
let person = {
key1: value1, ← property (note the colon :)
key2: value2, ← another property (separated by comma)
key3: value3 ← last property (NO comma at the end)
}; ← closing brace + semicolon| Part | What It Is |
|---|---|
firstName | The key (also called property name) |
"John" | The value (can be any data type) |
: | Separator between key and value |
, | Separator between properties |
{ } | The object container |
Values Can Be ANY Data Type
Object property values are not limited to strings and numbers. They can hold any JavaScript data type:
let student = {
name: "Adaeze", // string
age: 20, // number
isActive: true, // boolean
scores: [85, 92, 78, 90], // array
address: { city: "Abuja", zip: "900" }, // nested object
greet: function() { // function (called a "method")
return "Hello, I am " + this.name;
},
birthDate: null // null (no value yet)
};Spaces and Line Breaks Are Ignored
You can write an object on one line or multiple lines · JavaScript doesn't care. Long objects are usually written across multiple lines for readability:
// One line (for short objects):
let color = { red: 255, green: 128, blue: 0 };
// Multiple lines (for longer objects — preferred):
let product = {
name: "Wireless Headphones",
brand: "Sony",
price: 45000,
inStock: true,
rating: 4.5,
reviews: 128
};🤔 Thinking question: You have data about a car: brand is "Toyota", model is "Camry", year is 2023, and it has 4 doors. How would you write this as an object?
Two Ways to Access Properties
Once you have an object, you can read its properties in two ways:
Method 1 · Dot Notation (most common):
objectName.propertyNameMethod 2 · Bracket Notation:
objectName["propertyName"]Dot Notation · Clean and Readable
let person = {
firstName: "John",
lastName: "Doe",
age: 50,
eyeColor: "blue"
};
console.log(person.firstName); // "John"
console.log(person.age); // 50
console.log(person.eyeColor); // "blue"Step-by-step for person.firstName:
- Start with the object:
person - Use
.to access a property - Write the property name:
firstName - JavaScript looks inside
person, findsfirstName, and returns"John"
Bracket Notation · Flexible and Dynamic
console.log(person["firstName"]); // "John"
console.log(person["age"]); // 50When to prefer bracket notation:
- Property names with spaces or special characters:
let data = {
"full name": "Alice Okafor", // key has a space — only bracket notation works!
"phone-number": "080-1234567", // key has a hyphen
"2024score": 95 // key starts with a number
};
console.log(data["full name"]); // "Alice Okafor"
console.log(data["phone-number"]); // "080-1234567"
// data.full name ← ❌ Syntax error
// data.2024score ← ❌ Syntax error- Dynamic property access using variables:
let person = { name: "Alice", age: 30, city: "Lagos" };
let key = "age"; // key stored in a variable
console.log(person[key]); // 30 ← reads the value of 'key' first
// This is powerful when you don't know the property name ahead of time:
function getProperty(obj, propertyName) {
return obj[propertyName]; // dynamic access
}
console.log(getProperty(person, "name")); // "Alice"
console.log(getProperty(person, "city")); // "Lagos"⚠️ Common Beginner Mistake: Using
person["age"]vs.person[age]. The first reads the string key"age". The second reads whatever value is stored in the VARIABLE namedage. These are completely different!
let age = "name"; // variable holds "name"
console.log(person["age"]); // 30 (reads key literally: "age")
console.log(person[age]); // "Alice" (reads value of variable: "name" → person["name"])Nested Objects
An object property can itself be another object. You access nested properties by chaining dots or brackets:
let person = {
name: "Alice",
address: {
street: "12 Broad Street",
city: "Lagos",
state: "Lagos State",
zip: "100001"
}
};
// Access nested property:
console.log(person.address.city); // "Lagos"
console.log(person.address.street); // "12 Broad Street"
console.log(person["address"]["state"]); // "Lagos State" (bracket notation)Step-by-step for person.address.city:
person· access the person object.address· access theaddressproperty (which is also an object).city· access thecityproperty of that nested object- Returns
"Lagos"
Objects Inside Arrays Inside Objects
Real-world data structures are often deeply nested:
let company = {
name: "TechCorp Nigeria",
founded: 2015,
employees: [
{ name: "Alice", role: "CEO", salary: 800000 },
{ name: "Bob", role: "CTO", salary: 700000 },
{ name: "Chioma", role: "Engineer", salary: 400000 }
]
};
// Access first employee's name:
console.log(company.employees[0].name); // "Alice"
// Access second employee's role:
console.log(company.employees[1].role); // "CTO"
// Access third employee's salary:
console.log(company.employees[2].salary); // 400000
// Loop through all employees:
company.employees.forEach(emp => {
console.log(`${emp.name} — ${emp.role}`);
});
// Output:
// Alice — CEO
// Bob — CTO
// Chioma — EngineerWhat Is a Property?
A property is a key-value pair inside an object. The key is always a string (or Symbol), and the value can be anything.
let car = {
brand: "Toyota", // property: key="brand", value="Toyota"
model: "Camry", // property: key="model", value="Camry"
year: 2022 // property: key="year", value=2022
};Property Names (Keys)
Property names can be written with or without quotes:
// Without quotes (most common — works for simple names):
let obj = { name: "Alice", age: 30 };
// With quotes (required for special characters or reserved words):
let obj2 = {
"first name": "Alice", // space in key — MUST use quotes
"class": "A", // 'class' is a reserved word — safer with quotes
"2024": "year" // starts with a number — must use quotes
};✅ Best practice: Use simple names without quotes whenever possible. Reserve quotes for keys that have spaces, start with numbers, or use reserved JavaScript words.
Property Shorthand (ES6)
When the variable name matches the property key, you can use shorthand:
let name = "Alice";
let age = 30;
let city = "Lagos";
// Long way:
let person = { name: name, age: age, city: city };
// Shorthand (ES6) — when variable name === property name:
let person = { name, age, city };
console.log(person); // { name: "Alice", age: 30, city: "Lagos" }Computed Property Names (ES6)
You can use expressions as property names by wrapping them in [ ]:
let prefix = "user";
let id = 42;
let profile = {
[prefix + "_id"]: id, // key becomes "user_id"
[`${prefix}_active`]: true // key becomes "user_active"
};
console.log(profile); // { user_id: 42, user_active: true }Adding New Properties
You can add properties to an existing object at any time · just assign a value to a new key:
let person = { name: "Alice", age: 30 };
// Adding new properties:
person.city = "Lagos";
person.country = "Nigeria";
person["job"] = "Engineer";
console.log(person);
// { name: "Alice", age: 30, city: "Lagos", country: "Nigeria", job: "Engineer" }Modifying Existing Properties
Assign a new value to an existing key:
let person = { name: "Alice", age: 30, city: "Abuja" };
// Change city:
person.city = "Lagos";
person["age"] = 31;
console.log(person.city); // "Lagos" (was "Abuja")
console.log(person.age); // 31 (was 30)Deleting Properties · delete Operator
The delete keyword removes a property from an object completely:
let person = {
name: "Alice",
age: 30,
password: "secret123", // sensitive data we want to remove
city: "Lagos"
};
delete person.password; // removes the 'password' property
console.log(person);
// { name: "Alice", age: 30, city: "Lagos" } — password is gone!
console.log(person.password); // undefined (property no longer exists)⚠️ Important:
deleteonly works on object properties · NOT on regular variables declared withlet,const, orvar.
let x = 10;
delete x; // has no effect
console.log(x); // 10 (still exists)Checking If a Property Exists · in Operator
let person = { name: "Alice", age: 30 };
console.log("name" in person); // true
console.log("salary" in person); // false
console.log("age" in person); // true
// Useful in condition checks:
if ("salary" in person) {
console.log(`Salary: ${person.salary}`);
} else {
console.log("No salary information available.");
}
// Output: No salary information available.Optional Chaining ?. · Safe Property Access
When accessing deeply nested properties, a missing intermediate property causes an error. Optional chaining prevents this:
let person = {
name: "Alice",
address: {
city: "Lagos"
}
};
// ❌ This throws an error if 'address' doesn't exist:
// console.log(person.contact.phone); // TypeError: Cannot read property 'phone' of undefined
// ✅ Optional chaining — returns undefined instead of crashing:
console.log(person.address?.city); // "Lagos"
console.log(person.contact?.phone); // undefined (no error!)
console.log(person.job?.title); // undefined (no error!)What Is a Method?
A method is simply a function that belongs to an object. When a function is stored as an object property, it's called a method.
Think of it like this: an object's properties describe WHAT it is, and its methods describe WHAT IT CAN DO.
Object Properties (WHAT it is):
name: "Toyota"
model: "Camry"
year: 2022
Object Methods (WHAT IT CAN DO):
start() ← starts the engine
accelerate() ← speeds up
stop() ← stops the carDefining Methods
let person = {
firstName: "John",
lastName: "Doe",
age: 50,
fullName: function() {
return this.firstName + " " + this.lastName;
}
};
// Calling a method — like calling a function, but with dot notation:
console.log(person.fullName()); // "John Doe"Syntax difference:
- Property access:
person.firstName· no parentheses - Method call:
person.fullName()· WITH parentheses (it's a function call!)
⚠️ Common Beginner Mistake: Forgetting
()when calling a method:
console.log(person.fullName); // Returns the function definition itself (not the result!)
console.log(person.fullName()); // Returns "John Doe" ✅ES6 Method Shorthand
ES6 introduced a cleaner syntax for defining methods · you can omit the function keyword:
// Old way:
let calculator = {
add: function(a, b) { return a + b; },
subtract: function(a, b) { return a - b; }
};
// ES6 shorthand (preferred):
let calculator = {
add(a, b) { return a + b; },
subtract(a, b) { return a - b; },
multiply(a, b) { return a * b; }
};
console.log(calculator.add(5, 3)); // 8
console.log(calculator.subtract(10, 4)); // 6
console.log(calculator.multiply(3, 7)); // 21Methods Using this to Access Own Properties
Methods use this to access other properties of the same object:
let bankAccount = {
owner: "Emeka",
balance: 250000,
currency: "NGN",
deposit(amount) {
this.balance += amount;
return `Deposited ${amount}. New balance: ${this.balance} ${this.currency}`;
},
withdraw(amount) {
if (amount > this.balance) {
return "Insufficient funds!";
}
this.balance -= amount;
return `Withdrew ${amount}. New balance: ${this.balance} ${this.currency}`;
},
getStatement() {
return `Account Owner: ${this.owner} | Balance: ${this.currency} ${this.balance.toLocaleString()}`;
}
};
console.log(bankAccount.getStatement());
// Output: Account Owner: Emeka | Balance: NGN 250,000
console.log(bankAccount.deposit(50000));
// Output: Deposited 50000. New balance: 300000 NGN
console.log(bankAccount.withdraw(400000));
// Output: Insufficient funds!
console.log(bankAccount.withdraw(100000));
// Output: Withdrew 100000. New balance: 200000 NGNAdding Methods After Object Creation
Just like regular properties, methods can be added after an object is created:
let person = { name: "Alice", age: 30 };
// Add a method later:
person.greet = function() {
return `Hello! My name is ${this.name} and I am ${this.age} years old.`;
};
console.log(person.greet());
// Output: Hello! My name is Alice and I am 30 years old.What Is this?
this is a special keyword in JavaScript that refers to the object that is currently executing the code. It's like saying "me" or "my own" · it lets an object refer to itself.
Think of it like a name tag at a conference:
- When Alice is speaking, "my presentation" means ALICE's presentation.
- When Bob is speaking, "my presentation" means BOB's presentation.
thisworks the same way · it refers to whichever object is currently "speaking" (executing the code).
this in an Object Method
In a method, this refers to the object the method belongs to:
let person = {
firstName: "John",
lastName: "Doe",
id: 5566,
fullName() {
return this.firstName + " " + this.lastName;
// ↑ this = the person object
}
};
console.log(person.fullName()); // "John Doe"Why use this instead of person?
You might think: "Why not just write person.firstName inside the method?" The answer is: if you rename the variable or copy the object, this still works · but the hard-coded name breaks.
// ❌ Hard-coded object name inside method:
let person = {
name: "Alice",
greet() { return "Hello, I am " + person.name; } // tightly coupled to 'person'
};
let copy = person;
person = null; // original reference destroyed
copy.greet(); // ❌ Error! "person" is now null
// ✅ Using 'this' — safe and flexible:
let person = {
name: "Alice",
greet() { return "Hello, I am " + this.name; } // 'this' always points to the right object
};
let copy = person;
person = null;
copy.greet(); // ✅ "Hello, I am Alice"this Used Alone (Global Context)
When this is used outside of any object or function (at the top level of your code), it refers to the global object:
// In a browser:
console.log(this); // Window object (the global browser window)
console.log(this === window); // truethis in a Regular Function (Not a Method)
Inside a standalone function:
- In non-strict mode:
thisis the global object (windowin browser) - In strict mode (
"use strict"):thisisundefined
function showThis() {
console.log(this);
}
showThis(); // Window (in browser, non-strict)
"use strict";
function showStrict() {
console.log(this);
}
showStrict(); // undefined (strict mode)this in Event Handlers (HTML)
When a function is used as a DOM event handler, this refers to the HTML element that received the event:
<button onclick="this.style.color = 'red'">Click Me!</button>
<!-- 'this' = the button element -->this Keyword · What It Really Means. Open your editor, type the examples above by hand, modify them, and observe what changes.Summary Table · this Reference by Context
| Context | What this Refers To |
|---|---|
| Alone (top level) | Global object (window in browser) |
| Inside regular function | Global object (or undefined in strict mode) |
| Inside object method | The object that owns the method |
Inside constructor (new) | The newly created object |
| Inside arrow function | Inherited from enclosing scope (lexical) |
| Inside event handler | The HTML element that triggered the event |
With call() / apply() | Explicitly set to whatever you pass |
With bind() | Permanently bound to whatever you pass |
this in Methods · Demonstrated
let car = {
brand: "Toyota",
model: "Camry",
year: 2022,
describe() {
// 'this' = car object
return `${this.year} ${this.brand} ${this.model}`;
},
age() {
return 2025 - this.year;
}
};
console.log(car.describe()); // "2022 Toyota Camry"
console.log(car.age()); // 3The this Trap · Losing Context in Callbacks
One of the trickiest parts of this is that it can change when a method is called in a different context:
let person = {
name: "Alice",
friends: ["Bob", "Charlie"],
// ❌ Problem — 'this' inside forEach callback is NOT the person object:
listFriends() {
this.friends.forEach(function(friend) {
console.log(this.name + " knows " + friend); // 'this' is undefined here!
});
},
// ✅ Solution 1 — arrow function (inherits 'this' from listFriends):
listFriendsFixed() {
this.friends.forEach(friend => {
console.log(this.name + " knows " + friend); // 'this' = person ✅
});
}
};
person.listFriendsFixed();
// Output:
// Alice knows Bob
// Alice knows CharlieExplicit Binding · call(), apply(), bind()
You can manually control what this refers to:
function introduce() {
return `Hi! I'm ${this.name} from ${this.city}.`;
}
let person1 = { name: "Alice", city: "Lagos" };
let person2 = { name: "Bob", city: "Accra" };
// call() — call immediately, pass 'this' explicitly:
console.log(introduce.call(person1)); // "Hi! I'm Alice from Lagos."
console.log(introduce.call(person2)); // "Hi! I'm Bob from Accra."
// apply() — same as call, but args as array:
function greetWith(greeting, punctuation) {
return `${greeting}, I'm ${this.name}${punctuation}`;
}
console.log(greetWith.apply(person1, ["Hello", "!"])); // "Hello, I'm Alice!"
// bind() — returns a new function with 'this' permanently set:
let aliceIntro = introduce.bind(person1);
console.log(aliceIntro()); // "Hi! I'm Alice from Lagos."this in Different Contexts · The Full Picture. Open your editor, type the examples above by hand, modify them, and observe what changes.Why You Can't Just console.log() an Object as Text
Objects cannot be directly displayed as strings using simple concatenation:
let person = { name: "Alice", age: 30 };
console.log("The person is: " + person);
// Output: "The person is: [object Object]" ← NOT useful!JavaScript converts the object to the string "[object Object]" · which tells you it's an object, but nothing useful about its contents.
Technique 1 · console.log() (For Debugging)
The best tool for inspecting objects during development:
let person = { name: "Alice", age: 30, city: "Lagos" };
console.log(person);
// Output: { name: "Alice", age: 30, city: "Lagos" }
// Or use console.table() for a clean tabular view:
console.table(person);
// Output: displays as a table with "Key" and "Value" columnsTechnique 2 · JSON.stringify() (Object to String)
JSON.stringify() converts an object to a JSON string · the most reliable way to display the full contents of an object as text:
let person = { name: "Alice", age: 30, city: "Lagos" };
console.log(JSON.stringify(person));
// Output: '{"name":"Alice","age":30,"city":"Lagos"}'
// With formatting (2-space indentation for readable output):
console.log(JSON.stringify(person, null, 2));
// Output:
// {
// "name": "Alice",
// "age": 30,
// "city": "Lagos"
// }⚠️ Note:
JSON.stringify()cannot stringify functions orundefinedvalues · these are skipped:
let obj = { name: "Alice", greet: function() {} };
console.log(JSON.stringify(obj));
// Output: '{"name":"Alice"}' ← method is omittedTechnique 3 · Accessing Individual Properties
Display specific properties directly:
let person = { name: "Alice", age: 30, city: "Lagos" };
// Specific properties:
document.getElementById("name").innerHTML = person.name;
document.getElementById("age").innerHTML = person.age;
// In console:
console.log(`Name: ${person.name}, Age: ${person.age}, City: ${person.city}`);
// Output: Name: Alice, Age: 30, City: LagosTechnique 4 · for...in Loop (Display All Properties)
Loop through all properties and display them:
let person = { name: "Alice", age: 30, city: "Lagos", job: "Engineer" };
let output = "";
for (let key in person) {
output += `${key}: ${person[key]}\n`;
}
console.log(output);
// Output:
// name: Alice
// age: 30
// city: Lagos
// job: EngineerTechnique 5 · Object.keys(), Object.values(), Object.entries()
Modern methods for extracting object data as arrays:
let person = { name: "Alice", age: 30, city: "Lagos" };
console.log(Object.keys(person));
// ["name", "age", "city"]
console.log(Object.values(person));
// ["Alice", 30, "Lagos"]
console.log(Object.entries(person));
// [["name", "Alice"], ["age", 30], ["city", "Lagos"]]
// Display all entries using Object.entries():
Object.entries(person).forEach(([key, value]) => {
console.log(`${key} → ${value}`);
});
// Output:
// name → Alice
// age → 30
// city → Lagosfor...in · The Classic Object Loop
The for...in loop iterates over all enumerable (regular, non-hidden) properties of an object:
let car = {
brand: "Toyota",
model: "Camry",
year: 2022,
color: "Black"
};
for (let key in car) {
console.log(key + ": " + car[key]);
}
// Output:
// brand: Toyota
// model: Camry
// year: 2022
// color: BlackStep-by-step for for (let key in car):
keytakes the value of the first property name:"brand"car[key]→car["brand"]→"Toyota"- Prints
"brand: Toyota" keymoves to"model", prints"model: Camry"- Continues for each property
⚠️ Warning:
for...inalso loops through inherited properties. To be safe, use.hasOwnProperty()to check if a property belongs directly to the object:
for (let key in car) {
if (car.hasOwnProperty(key)) {
console.log(key + ": " + car[key]);
}
}Looping Through Nested Objects
let company = {
name: "TechCorp",
address: { city: "Lagos", state: "Lagos State" },
staff: 150
};
for (let key in company) {
if (typeof company[key] === "object" && company[key] !== null) {
console.log(`${key}:`);
for (let subKey in company[key]) {
console.log(` ${subKey}: ${company[key][subKey]}`);
}
} else {
console.log(`${key}: ${company[key]}`);
}
}
// Output:
// name: TechCorp
// address:
// city: Lagos
// state: Lagos State
// staff: 150Real-World Use · Building HTML from an Object
let product = {
name: "Wireless Headphones",
brand: "Sony",
price: 45000,
rating: 4.5,
inStock: true
};
let html = "<ul>";
for (let key in product) {
html += `<li><strong>${key}:</strong> ${product[key]}</li>`;
}
html += "</ul>";
// Results in a proper HTML list of all product detailsThe Problem Constructor Functions Solve
What if you need to create 100 similar objects · like 100 student profiles? Creating each one manually with a literal would be tedious and error-prone:
// 😩 Tedious — doing this 100 times:
let student1 = { name: "Alice", grade: "A", score: 92, passed: true };
let student2 = { name: "Bob", grade: "C", score: 68, passed: true };
let student3 = { name: "Chioma", grade: "F", score: 35, passed: false };
// ... × 97 more timesConstructor functions solve this by providing a blueprint (template) for creating objects of the same structure:
Writing a Constructor Function
A constructor function is a regular function with two special characteristics:
- Its name starts with a Capital Letter (convention)
- It is called with the
newkeyword
function Person(firstName, lastName, age, eyeColor) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
this.eyeColor = eyeColor;
}Syntax breakdown:
function Person(firstName, lastName) {
// ↑ Capital letter = it's a constructor
this.firstName = firstName;
// ↑ 'this' = the new object being created
// 'this.firstName' = sets a property on the new object
// '= firstName' = uses the value passed in as argument
}Using new to Create Objects (Instances)
Call the constructor with new to create each object (called an instance):
let person1 = new Person("John", "Doe", 50, "blue");
let person2 = new Person("Sally", "Rally", 48, "green");
let person3 = new Person("Emeka", "Obi", 25, "brown");
console.log(person1.firstName); // "John"
console.log(person2.age); // 48
console.log(person3.eyeColor); // "brown"What new does behind the scenes:
- Creates a new empty object
{} - Sets
thisto point to that new object - Runs the constructor function (fills in the properties)
- Returns the new object automatically
Step-by-step for new Person("John", "Doe", 50, "blue"):
1. new creates: {}
2. this = {}
3. this.firstName = "John" → { firstName: "John" }
4. this.lastName = "Doe" → { firstName: "John", lastName: "Doe" }
5. this.age = 50 → { ..., age: 50 }
6. this.eyeColor = "blue" → { ..., eyeColor: "blue" }
7. Returns the filled object → person1Adding Methods to a Constructor
Methods can be added inside the constructor the same way properties are:
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
// Method defined inside constructor:
this.fullName = function() {
return this.firstName + " " + this.lastName;
};
this.isAdult = function() {
return this.age >= 18;
};
}
let person1 = new Person("John", "Doe", 50);
let person2 = new Person("Mary", "Smith", 15);
console.log(person1.fullName()); // "John Doe"
console.log(person1.isAdult()); // true
console.log(person2.isAdult()); // falseAdding Properties to a Specific Instance
You can add unique properties to one specific object after creation · this only affects THAT instance, not all objects made by the constructor:
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
let alice = new Person("Alice", "Okafor");
let bob = new Person("Bob", "Mensah");
// Add property only to alice:
alice.nationality = "Nigerian";
console.log(alice.nationality); // "Nigerian"
console.log(bob.nationality); // undefined (bob doesn't have this)A Complete Constructor Example
function BankAccount(owner, initialBalance, accountType = "Savings") {
this.owner = owner;
this.balance = initialBalance;
this.accountType = accountType;
this.transactions = [];
this.deposit = function(amount) {
if (amount <= 0) return "Amount must be positive";
this.balance += amount;
this.transactions.push({ type: "deposit", amount, date: new Date().toLocaleDateString() });
return `Deposited ₦${amount.toLocaleString()}. Balance: ₦${this.balance.toLocaleString()}`;
};
this.withdraw = function(amount) {
if (amount > this.balance) return "Insufficient funds";
this.balance -= amount;
this.transactions.push({ type: "withdrawal", amount, date: new Date().toLocaleDateString() });
return `Withdrew ₦${amount.toLocaleString()}. Balance: ₦${this.balance.toLocaleString()}`;
};
this.getStatement = function() {
return `${this.owner}'s ${this.accountType} Account | Balance: ₦${this.balance.toLocaleString()}`;
};
}
let account1 = new BankAccount("Emeka Obi", 100000);
let account2 = new BankAccount("Amara Nwosu", 50000, "Current");
console.log(account1.getStatement()); // Emeka Obi's Savings Account | Balance: ₦100,000
console.log(account1.deposit(25000)); // Deposited ₦25,000. Balance: ₦125,000
console.log(account1.withdraw(200000)); // Insufficient funds
console.log(account2.getStatement()); // Amara Nwosu's Current Account | Balance: ₦50,000Convention 1 · Capital First Letter
Constructor functions always start with a capital letter to signal: "this is a constructor, use new with it."
// ✅ Constructor:
function Car(brand, model) { ... }
// ✅ Regular function:
function calculateTax(price) { ... }Convention 2 · Always Use new
Calling a constructor WITHOUT new is a silent disaster · this becomes the global object:
function Person(name) {
this.name = name;
}
let p1 = new Person("Alice"); // ✅ Correct — creates a Person object
let p2 = Person("Bob"); // ❌ Wrong — no 'new', runs as regular function
// 'this' = window, sets window.name = "Bob"!
console.log(p1.name); // "Alice"
console.log(p2); // undefined (function returns nothing)Convention 3 · Use instanceof to Check the Type
function Car(brand) {
this.brand = brand;
}
let myCar = new Car("Toyota");
console.log(myCar instanceof Car); // true
console.log(myCar instanceof Object); // true (all objects are instances of Object)
let myStr = "Hello";
console.log(myStr instanceof Car); // falseConvention 4 · Prototype for Shared Methods (Advanced Preview)
When you define methods inside the constructor, every new instance gets its own COPY of that method · this uses extra memory. The more efficient approach is to put shared methods on the prototype:
function Person(name, age) {
this.name = name; // own property (unique per instance)
this.age = age;
}
// Method on prototype — shared by ALL instances (memory efficient):
Person.prototype.greet = function() {
return `Hi, I'm ${this.name}!`;
};
let p1 = new Person("Alice", 30);
let p2 = new Person("Bob", 25);
console.log(p1.greet()); // "Hi, I'm Alice!"
console.log(p2.greet()); // "Hi, I'm Bob!"
// Both p1 and p2 SHARE the same greet function in memory:
console.log(p1.greet === p2.greet); // true (same function reference!)JavaScript comes with many built-in constructors that create objects of specific types. You already use them!
// These are all constructors:
let str = new String("Hello"); // String object
let num = new Number(42); // Number object
let bool = new Boolean(true); // Boolean object
let arr = new Array(1, 2, 3); // Array object
let obj = new Object({ a: 1 }); // Object object
let date = new Date(); // Date object
let regex = new RegExp("\\d+"); // RegExp object
let func = new Function("return 1"); // Function object
let map = new Map(); // Map object
let set = new Set(); // Set object⚠️ Important: For primitive types (String, Number, Boolean), you should almost NEVER use the
newconstructor form · use literals instead. The constructors create OBJECTS, not primitives, which causes comparison issues:
// ❌ Object form — causes problems:
let s1 = new String("Hello");
let s2 = new String("Hello");
console.log(s1 === s2); // false (two different objects!)
console.log(typeof s1); // "object"
// ✅ Literal form — always preferred:
let s3 = "Hello";
let s4 = "Hello";
console.log(s3 === s4); // true
console.log(typeof s3); // "string"Exceptions · These constructors ARE useful:
// ✅ Date — no literal form, must use constructor:
let today = new Date();
let birthday = new Date("1999-05-15");
// ✅ Map and Set — use constructors:
let myMap = new Map();
let mySet = new Set([1, 2, 3, 3]); // duplicates removed
// ✅ RegExp — for dynamic patterns:
let pattern = new RegExp("hello", "i");What Is a Primitive?
A primitive is a simple, single value · not an object. JavaScript has 7 primitive types: string, number, bigint, boolean, undefined, null, symbol.
Primitives are immutable · when you "change" a primitive, you actually create a NEW value:
let name = "Alice";
name = "Bob"; // not changing "Alice" — creating a new string "Bob" and reassigning 'name'Objects Are Mutable References
Objects live in memory at a specific address. When you assign an object to a variable, you're storing the memory address (reference), not the object itself:
let person1 = { name: "Alice" };
let person2 = person1; // person2 now holds the SAME reference!
person2.name = "Bob"; // changes the object in memory
console.log(person1.name); // "Bob" ← person1 also changed!
console.log(person2.name); // "Bob"
// Both variables point to the SAME object in memoryVisualizing the difference:
Primitives (pass by value):
let a = 5; → [a: 5]
let b = a; → [a: 5] [b: 5] (separate copies)
b = 10; → [a: 5] [b: 10] (a is unchanged)
Objects (pass by reference):
let obj1 = {x: 1}; → [obj1] → {x: 1} in memory
let obj2 = obj1; → [obj1] → same {x: 1}
[obj2] ↗
obj2.x = 99; → [obj1] → {x: 99}
[obj2] ↗ (BOTH see the change!)Comparing Objects
Two objects are NEVER equal just because they look the same · they must be the SAME object in memory:
let a = { x: 1 };
let b = { x: 1 };
let c = a;
console.log(a === b); // false (different objects in memory, even with same content)
console.log(a === c); // true (same reference)
console.log(a == b); // false (same result with ==)Object.keys(obj) · Get All Property Names
Returns an array of the object's own property names:
let person = { name: "Alice", age: 30, city: "Lagos" };
let keys = Object.keys(person);
console.log(keys); // ["name", "age", "city"]
console.log(keys.length); // 3 (number of properties)Object.values(obj) · Get All Property Values
Returns an array of the object's own property values:
let person = { name: "Alice", age: 30, city: "Lagos" };
let values = Object.values(person);
console.log(values); // ["Alice", 30, "Lagos"]
// Use case — sum all values in an object:
let scores = { math: 85, english: 72, science: 90 };
let total = Object.values(scores).reduce((sum, score) => sum + score, 0);
console.log(total); // 247Object.entries(obj) · Get Key-Value Pairs
Returns an array of [key, value] pairs:
let person = { name: "Alice", age: 30, city: "Lagos" };
let entries = Object.entries(person);
console.log(entries);
// [["name", "Alice"], ["age", 30], ["city", "Lagos"]]
// Loop with destructuring:
for (let [key, value] of Object.entries(person)) {
console.log(`${key} = ${value}`);
}
// Output:
// name = Alice
// age = 30
// city = LagosObject.assign(target, source) · Copy Properties
Copies properties from one or more source objects into a target object:
let target = { a: 1, b: 2 };
let source = { b: 4, c: 5 }; // 'b' will overwrite target's 'b'
Object.assign(target, source);
console.log(target); // { a: 1, b: 4, c: 5 }
// Create a new merged object (common use):
let merged = Object.assign({}, target, source);Object.freeze(obj) · Make Object Immutable
Prevents any modifications to an object:
let config = { theme: "dark", lang: "en", debug: false };
Object.freeze(config);
config.theme = "light"; // silently fails (or error in strict mode)
config.newProp = "value"; // silently fails
delete config.lang; // silently fails
console.log(config.theme); // "dark" (unchanged!)Object.create(proto) · Create Object with Specific Prototype
let animal = {
speak() {
return `${this.name} makes a sound.`;
}
};
let dog = Object.create(animal);
dog.name = "Rex";
dog.breed = "German Shepherd";
console.log(dog.speak()); // "Rex makes a sound." (method inherited from animal)
console.log(dog.name); // "Rex"
console.log(dog.hasOwnProperty("name")); // true (own property)
console.log(dog.hasOwnProperty("speak")); // false (inherited, not own)Shallow Copy · Spread Operator {...obj}
The spread operator copies all own enumerable properties into a new object:
let original = { name: "Alice", age: 30, city: "Lagos" };
let copy = { ...original };
copy.name = "Bob"; // modifying the copy
console.log(original.name); // "Alice" ← original unchanged ✅
console.log(copy.name); // "Bob"⚠️ Shallow copy limitation: Nested objects are still shared by reference:
let original = { name: "Alice", address: { city: "Lagos" } };
let copy = { ...original };
copy.address.city = "Abuja"; // changes the NESTED object
console.log(original.address.city); // "Abuja" ← original also changed! ⚠️Deep Copy · JSON.parse(JSON.stringify(obj))
For truly independent copies (including nested objects), use JSON conversion (works for most data):
let original = { name: "Alice", address: { city: "Lagos" }, scores: [85, 90] };
let deepCopy = JSON.parse(JSON.stringify(original));
deepCopy.address.city = "Abuja";
deepCopy.scores.push(95);
console.log(original.address.city); // "Lagos" ← safe! ✅
console.log(original.scores); // [85, 90] ← safe! ✅⚠️ Limitation:
JSON.stringifyskips functions,undefined, andSymbolproperties.
Merging Objects · Spread Operator
let defaults = { theme: "light", lang: "en", fontSize: 14 };
let userPrefs = { theme: "dark", fontSize: 16 };
// Merge — userPrefs values override defaults:
let settings = { ...defaults, ...userPrefs };
console.log(settings);
// { theme: "dark", lang: "en", fontSize: 16 }
// ↑ overridden ↑ kept ↑ overridden
// Add extra properties during merge:
let finalSettings = { ...defaults, ...userPrefs, version: "2.0" };
console.log(finalSettings.version); // "2.0"🏋️ Exercise 1 · Product Catalog Builder
Objective: Practice object creation, property access, methods, and this.
Real-world Scenario: You are building a product catalog for an online store. Each product needs to store data and compute discounted prices.
Warm-up Mini-Example:
let item = {
name: "Pen",
price: 200,
getDiscounted(pct) { return this.price * (1 - pct); }
};
console.log(item.getDiscounted(0.1)); // 180Your Exercise:
Build a product object with the following properties and methods:
// Create this object:
let laptop = {
name: "HP Pavilion",
brand: "HP",
price: 320000, // in Naira
category: "Electronics",
stock: 15,
rating: 4.2,
reviews: 87,
// Methods to implement:
// 1. getDiscountedPrice(discountPercent) - returns price after discount
// 2. isAffordable(budget) - returns true if price <= budget
// 3. restock(quantity) - adds quantity to stock, returns new stock
// 4. getSummary() - returns a full formatted summary string
};Step-by-step Instructions:
- Implement all four methods using
thisto access properties - Test each method with different inputs
- Add a new property
lastUpdatedafter the object is created - Use
JSON.stringify()to display the full object
Expected Output:
=== Product: HP Pavilion ===
Price: ₦320,000.00
After 15% off: ₦272,000.00
Affordable for ₦300k budget: false
Affordable for ₦350k budget: true
Stock before restock: 15
Stock after restock (+20): 35
Summary:
HP Pavilion by HP | ₦320,000 | ★ 4.2 (87 reviews) | In stock: 35 units
Full object (JSON):
{ "name": "HP Pavilion", "brand": "HP", ... }Self-Check Questions:
- What does
this.pricerefer to inside a method? - What happens if you call
getDiscountedPrice(1.5)? Should you validate inputs? - How would you add a second product and compare them?
🏋️ Exercise 2 · Student Registry with Constructor
Objective: Practice constructor functions, new, instance creation, and object arrays.
Real-world Scenario: A school registry system needs to create and manage student records consistently. Using a constructor ensures every record has the same structure.
Warm-up Mini-Example:
function Animal(name, sound) {
this.name = name;
this.sound = sound;
this.speak = function() { return `${this.name} says ${this.sound}!`; };
}
let dog = new Animal("Rex", "Woof");
console.log(dog.speak()); // "Rex says Woof!"Your Exercise:
Build a Student constructor function, then create a class registry:
Step-by-step Instructions:
- Write
function Student(id, name, age, subjects)wheresubjectsis an array - Add these methods to the constructor:
- addScore(subject, score) · adds { subject, score } to a scores array - getAverage() · returns average of all scores - getGrade() · returns letter grade based on average - getProfile() · returns formatted profile string
- Create at least 4 student instances
- Store them in an array called
registry - Loop through registry to display all profiles
- Find the student with the highest average
Expected Output:
=== School Registry ===
Student #001: Adaeze Okonkwo, Age 20
Subjects: Mathematics, English, Sciences
Average Score: 84.7 → Grade: B
Student #002: Babatunde Lawal, Age 22
Subjects: Physics, Chemistry, Biology
Average Score: 61.3 → Grade: C
...
🏆 Top Student: Cynthia Asante (Average: 92.4, Grade: A)What-if Challenge: What happens if a student has NO scores yet? Handle this edge case in getAverage().
🏋️ Exercise 3 · Object Inspector Utility
Objective: Practice for...in, Object.keys(), Object.values(), Object.entries(), JSON.stringify(), and typeof.
Real-world Scenario: A developer tool needs to inspect any JavaScript object and produce a detailed, human-readable report · like a debugging assistant.
Warm-up Mini-Example:
function countProperties(obj) {
return Object.keys(obj).length;
}
let car = { brand: "Toyota", model: "Camry", year: 2022 };
console.log(countProperties(car)); // 3Your Exercise:
Write a inspect(obj, label) function that:
- Prints the label as a header
- Shows total property count
- Lists all keys with their values AND their types
- Identifies which properties are methods (functions)
- Shows a JSON representation (excluding methods)
Expected Output for a person object:
=== Inspector: Person Object ===
Total Properties: 6
Property Details:
firstName : "Alice" [string]
lastName : "Okafor" [string]
age : 30 [number]
city : "Lagos" [string]
isActive : true [boolean]
greet : function [function] ← method
Data Properties: 5
Methods Found: 1
JSON Snapshot:
{
"firstName": "Alice",
"lastName": "Okafor",
"age": 30,
"city": "Lagos",
"isActive": true
}📚 Project Overview
You will build a Library Management System using all object concepts from this tutorial. The system manages books, members, and borrowing transactions.
What you'll practice: Object literals, constructors, this, methods, property access, for...in, Object.keys/values/entries, spread/copy, JSON.stringify, and object arrays.
Stage 1 · Book Constructor and Catalog
Illustrative Preview:
function Book(title, author, year) {
this.title = title;
this.author = author;
this.year = year;
this.available = true;
}
let book1 = new Book("Things Fall Apart", "Chinua Achebe", 1958);
console.log(book1.title); // "Things Fall Apart"Lesson 10 complete! 🎉
You covered:
- ✅ 1. What Is an Object? The Big Picture
- ✅ 2. Creating Objects · Object Literals
- ✅ 3. Accessing Object Properties
- ✅ 4. Nested Objects and Nested Arrays
- ✅ 5. Object Properties · Deep Dive
- ✅ 6. Adding, Modifying, and Deleting Properties
- ✅ 7. Object Methods · Functions as Properties
- ✅ 8. The `this` Keyword · What It Really Means