Learn to work with objects, arrays, and modern JavaScript data structures.
Learn to work with objects, arrays, and modern JavaScript data structures.
Learn to create and manipulate objects, understand properties, and master object-oriented programming in JavaScript
Content by: Meet Bhimani
React.js Developer
Objects are the fundamental building blocks of JavaScript. They are collections of key-value pairs that can represent real-world entities, data structures, or any complex data.
// 1. Object Literals (Most Common)
const person = {
name: "John Doe",
age: 30,
email: "john@example.com",
greet() {
return `Hello, my name is ${this.name}`;
}
};
console.log(person.name); // "John Doe"
console.log(person.greet()); // "Hello, my name is John Doe"
// 2. Constructor Functions
function Person(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
this.greet = function() {
return `Hello, my name is ${this.name}`;
};
}
const john = new Person("John Doe", 30, "john@example.com");
const jane = new Person("Jane Smith", 25, "jane@example.com");
console.log(john.greet()); // "Hello, my name is John Doe"
console.log(jane.greet()); // "Hello, my name is Jane Smith"
// 3. Object.create()
const personProto = {
greet() {
return `Hello, my name is ${this.name}`;
}
};
const alice = Object.create(personProto);
alice.name = "Alice Johnson";
alice.age = 28;
console.log(alice.greet()); // "Hello, my name is Alice Johnson"
// 4. Class Syntax (ES6+)
class PersonClass {
constructor(name, age, email) {
this.name = name;
this.age = age;
this.email = email;
}
greet() {
return `Hello, my name is ${this.name}`;
}
getAge() {
return this.age;
}
}
const bob = new PersonClass("Bob Wilson", 35, "bob@example.com");
console.log(bob.greet()); // "Hello, my name is Bob Wilson"
// 5. Factory Functions
function createPerson(name, age, email) {
return {
name,
age,
email,
greet() {
return `Hello, my name is ${this.name}`;
},
getAge() {
return this.age;
}
};
}
const charlie = createPerson("Charlie Brown", 40, "charlie@example.com");
console.log(charlie.greet()); // "Hello, my name is Charlie Brown"
// Object property access
const user = {
firstName: "John",
lastName: "Doe",
age: 30,
"full name": "John Doe", // Property with spaces
address: {
street: "123 Main St",
city: "New York",
zipCode: "10001"
},
hobbies: ["reading", "coding", "gaming"],
greet() {
return `Hello, I'm ${this.firstName} ${this.lastName}`;
}
};
// Dot notation
console.log(user.firstName); // "John"
console.log(user.age); // 30
console.log(user.greet()); // "Hello, I'm John Doe"
// Bracket notation
console.log(user["firstName"]); // "John"
console.log(user["full name"]); // "John Doe" (for properties with spaces)
console.log(user["age"]); // 30
// Nested object access
console.log(user.address.city); // "New York"
console.log(user["address"]["city"]); // "New York"
// Array property access
console.log(user.hobbies[0]); // "reading"
console.log(user.hobbies.length); // 3
// Adding properties
user.email = "john@example.com";
user["phone"] = "555-1234";
console.log(user.email); // "john@example.com"
console.log(user.phone); // "555-1234"
// Deleting properties
delete user.age;
console.log(user.age); // undefined
// Checking if property exists
console.log("firstName" in user); // true
console.log("age" in user); // false
console.log(user.hasOwnProperty("firstName")); // true
console.log(user.hasOwnProperty("toString")); // false (inherited)
// Object methods and 'this' context
const calculator = {
value: 0,
add(num) {
this.value += num;
return this;
},
subtract(num) {
this.value -= num;
return this;
},
multiply(num) {
this.value *= num;
return this;
},
divide(num) {
if (num !== 0) {
this.value /= num;
} else {
console.error("Cannot divide by zero");
}
return this;
},
getValue() {
return this.value;
},
reset() {
this.value = 0;
return this;
}
};
// Method chaining
const result = calculator
.add(10)
.multiply(2)
.subtract(5)
.divide(3)
.getValue();
console.log(result); // 5
// 'this' context issues
const user = {
name: "John",
greet() {
return `Hello, ${this.name}!`;
}
};
console.log(user.greet()); // "Hello, John!"
// 'this' context lost when method is assigned to variable
const greetFunction = user.greet;
console.log(greetFunction()); // "Hello, undefined!"
// Solutions for 'this' context
// 1. Arrow functions (lexical 'this')
const user2 = {
name: "Jane",
greet: () => {
return `Hello, ${this.name}!`; // 'this' refers to global scope
}
};
// 2. Bind method
const user3 = {
name: "Bob",
greet() {
return `Hello, ${this.name}!`;
}
};
const boundGreet = user3.greet.bind(user3);
console.log(boundGreet()); // "Hello, Bob!"
// 3. Call and Apply methods
const user4 = {
name: "Alice"
};
function greet(greeting) {
return `${greeting}, ${this.name}!`;
}
console.log(greet.call(user4, "Hi")); // "Hi, Alice!"
console.log(greet.apply(user4, ["Hello"])); // "Hello, Alice!"
// Exercise: Create a Book Management System
// 1. Create a Book class
class Book {
constructor(title, author, year, isbn) {
this.title = title;
this.author = author;
this.year = year;
this.isbn = isbn;
this.isAvailable = true;
}
borrow() {
if (this.isAvailable) {
this.isAvailable = false;
return `${this.title} has been borrowed.`;
} else {
return `${this.title} is not available.`;
}
}
return() {
this.isAvailable = true;
return `${this.title} has been returned.`;
}
getInfo() {
return `${this.title} by ${this.author} (${this.year}) - ISBN: ${this.isbn}`;
}
}
// 2. Create a Library class
class Library {
constructor(name) {
this.name = name;
this.books = [];
}
addBook(book) {
this.books.push(book);
return `${book.title} added to ${this.name}`;
}
removeBook(isbn) {
const index = this.books.findIndex(book => book.isbn === isbn);
if (index !== -1) {
const removedBook = this.books.splice(index, 1)[0];
return `${removedBook.title} removed from ${this.name}`;
}
return "Book not found";
}
findBook(isbn) {
return this.books.find(book => book.isbn === isbn);
}
listAvailableBooks() {
return this.books.filter(book => book.isAvailable);
}
getBookCount() {
return this.books.length;
}
}
// 3. Test the system
const library = new Library("My Library");
const book1 = new Book("JavaScript Guide", "John Doe", 2023, "123-456-789");
const book2 = new Book("React Basics", "Jane Smith", 2024, "987-654-321");
const book3 = new Book("Node.js Advanced", "Bob Wilson", 2023, "456-789-123");
library.addBook(book1);
library.addBook(book2);
library.addBook(book3);
console.log("Library:", library.name);
console.log("Total books:", library.getBookCount());
console.log(book1.borrow());
console.log(book2.borrow());
console.log(book1.return());
console.log("Available books:", library.listAvailableBooks().length);
// 4. Challenge: Add more features
// - Search books by title or author
// - Track borrowing history
// - Calculate overdue fees
// - Add categories/genres
Test your understanding of this topic:
Master JavaScript arrays, their methods, and modern array manipulation techniques
Content by: Ashish Kava
MERN Stack Developer
Arrays are ordered collections of values that can store any type of data. JavaScript provides a rich set of methods for manipulating arrays.
// Array creation methods
// 1. Array literal
const fruits = ["apple", "banana", "orange"];
const numbers = [1, 2, 3, 4, 5];
const mixed = [1, "hello", true, { name: "John" }];
// 2. Array constructor
const colors = new Array("red", "green", "blue");
const emptyArray = new Array(5); // Creates array with 5 empty slots
// 3. Array.from()
const arrayFromString = Array.from("hello"); // ["h", "e", "l", "l", "o"]
const arrayFromSet = Array.from(new Set([1, 2, 2, 3])); // [1, 2, 3]
// 4. Spread operator
const original = [1, 2, 3];
const copy = [...original]; // [1, 2, 3]
// Array access
console.log(fruits[0]); // "apple"
console.log(fruits[fruits.length - 1]); // "orange"
// Array length
console.log(fruits.length); // 3
// Array modification
fruits[1] = "grape"; // ["apple", "grape", "orange"]
fruits.push("mango"); // Add to end
fruits.unshift("kiwi"); // Add to beginning
fruits.pop(); // Remove from end
fruits.shift(); // Remove from beginning
console.log(fruits); // ["grape", "orange"]
// Array methods in action
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 1. map() - Transform elements
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
const users = [
{ name: "John", age: 25 },
{ name: "Jane", age: 30 },
{ name: "Bob", age: 35 }
];
const names = users.map(user => user.name);
console.log(names); // ["John", "Jane", "Bob"]
// 2. filter() - Select elements
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6, 8, 10]
const adults = users.filter(user => user.age >= 30);
console.log(adults); // [{ name: "Jane", age: 30 }, { name: "Bob", age: 35 }]
// 3. reduce() - Accumulate values
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 55
const totalAge = users.reduce((total, user) => total + user.age, 0);
console.log(totalAge); // 90
// 4. forEach() - Execute for each element
numbers.forEach((num, index) => {
console.log(`Number ${index + 1}: ${num}`);
});
// 5. find() & findIndex() - Search elements
const firstEven = numbers.find(num => num % 2 === 0);
console.log(firstEven); // 2
const janeIndex = users.findIndex(user => user.name === "Jane");
console.log(janeIndex); // 1
// 6. some() & every() - Test conditions
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true
const allAdults = users.every(user => user.age >= 18);
console.log(allAdults); // true
// 7. includes() & indexOf() - Check existence
console.log(numbers.includes(5)); // true
console.log(numbers.indexOf(5)); // 4
console.log(numbers.indexOf(99)); // -1 (not found)
// 8. slice() & splice() - Extract and modify
const firstThree = numbers.slice(0, 3);
console.log(firstThree); // [1, 2, 3]
const numbersCopy = [...numbers];
numbersCopy.splice(2, 2, 99, 100); // Remove 2 elements starting at index 2, insert 99, 100
console.log(numbersCopy); // [1, 2, 99, 100, 5, 6, 7, 8, 9, 10]
// 9. sort() & reverse() - Order elements
const fruits = ["banana", "apple", "orange"];
fruits.sort();
console.log(fruits); // ["apple", "banana", "orange"]
const scores = [85, 92, 78, 96, 88];
scores.sort((a, b) => b - a); // Sort in descending order
console.log(scores); // [96, 92, 88, 85, 78]
// 10. join() & split() - String conversion
const words = ["hello", "world", "javascript"];
const sentence = words.join(" ");
console.log(sentence); // "hello world javascript"
const text = "apple,banana,orange";
const fruitArray = text.split(",");
console.log(fruitArray); // ["apple", "banana", "orange"]
// Modern array features
// 1. Destructuring
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// 2. Array.from() with mapping
const squares = Array.from([1, 2, 3, 4], x => x * x);
console.log(squares); // [1, 4, 9, 16]
// 3. Array.of() - Creates array from arguments
const array1 = Array.of(1, 2, 3);
const array2 = Array.of(5); // [5] (not [,,,,,])
console.log(array1); // [1, 2, 3]
console.log(array2); // [5]
// 4. find() and findIndex()
const users = [
{ id: 1, name: "John" },
{ id: 2, name: "Jane" },
{ id: 3, name: "Bob" }
];
const user = users.find(u => u.id === 2);
console.log(user); // { id: 2, name: "Jane" }
// 5. flat() and flatMap() - ES2019
const nested = [1, [2, 3], [4, [5, 6]]];
const flattened = nested.flat();
console.log(flattened); // [1, 2, 3, 4, [5, 6]]
const deeplyFlattened = nested.flat(2);
console.log(deeplyFlattened); // [1, 2, 3, 4, 5, 6]
// 6. Array methods with arrow functions
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(evens); // [2, 4]
console.log(sum); // 15
// 7. Array spread operator
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// 8. Array rest parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// Exercise: Build a Todo List Application
// 1. Create Todo class
class Todo {
constructor(title, description = "", priority = "medium") {
this.id = Date.now() + Math.random();
this.title = title;
this.description = description;
this.priority = priority;
this.completed = false;
this.createdAt = new Date();
}
toggle() {
this.completed = !this.completed;
return this.completed;
}
update(updates) {
Object.assign(this, updates);
}
}
// 2. Create TodoList class
class TodoList {
constructor() {
this.todos = [];
}
addTodo(title, description, priority) {
const todo = new Todo(title, description, priority);
this.todos.push(todo);
return todo;
}
removeTodo(id) {
const index = this.todos.findIndex(todo => todo.id === id);
if (index !== -1) {
return this.todos.splice(index, 1)[0];
}
return null;
}
getTodo(id) {
return this.todos.find(todo => todo.id === id);
}
getAllTodos() {
return [...this.todos];
}
getCompletedTodos() {
return this.todos.filter(todo => todo.completed);
}
getPendingTodos() {
return this.todos.filter(todo => !todo.completed);
}
getTodosByPriority(priority) {
return this.todos.filter(todo => todo.priority === priority);
}
searchTodos(query) {
return this.todos.filter(todo =>
todo.title.toLowerCase().includes(query.toLowerCase()) ||
todo.description.toLowerCase().includes(query.toLowerCase())
);
}
getStats() {
const total = this.todos.length;
const completed = this.getCompletedTodos().length;
const pending = this.getPendingTodos().length;
return {
total,
completed,
pending,
completionRate: total > 0 ? (completed / total * 100).toFixed(1) : 0
};
}
}
// 3. Test the Todo List
const todoList = new TodoList();
todoList.addTodo("Learn JavaScript", "Complete the JavaScript course", "high");
todoList.addTodo("Buy groceries", "Milk, bread, eggs", "medium");
todoList.addTodo("Exercise", "30 minutes cardio", "low");
todoList.addTodo("Read book", "Finish the current novel", "medium");
console.log("All todos:", todoList.getAllTodos().length);
console.log("Pending todos:", todoList.getPendingTodos().length);
// Complete a todo
const firstTodo = todoList.getAllTodos()[0];
firstTodo.toggle();
console.log("Completed todos:", todoList.getCompletedTodos().length);
console.log("Stats:", todoList.getStats());
// Search todos
const searchResults = todoList.searchTodos("javascript");
console.log("Search results:", searchResults);
// Get todos by priority
const highPriority = todoList.getTodosByPriority("high");
console.log("High priority todos:", highPriority.length);
Test your understanding of this topic:
Master modern JavaScript collections including Sets, Maps, WeakSets, and WeakMaps for efficient data handling
Content by: Ronak Macwan
JavaScript Developer
ES6 introduced new collection types that provide better alternatives to traditional objects and arrays for specific use cases.
// Set - Collection of unique values
const uniqueNumbers = new Set([1, 2, 2, 3, 3, 4, 5]);
console.log(uniqueNumbers); // Set {1, 2, 3, 4, 5}
// Set methods
const fruits = new Set();
// Add elements
fruits.add("apple");
fruits.add("banana");
fruits.add("apple"); // Duplicate ignored
console.log(fruits); // Set {"apple", "banana"}
// Check if element exists
console.log(fruits.has("apple")); // true
console.log(fruits.has("orange")); // false
// Remove element
fruits.delete("banana");
console.log(fruits); // Set {"apple"}
// Get size
console.log(fruits.size); // 1
// Clear all elements
fruits.clear();
console.log(fruits.size); // 0
// Set iteration
const colors = new Set(["red", "green", "blue"]);
colors.forEach(color => console.log(color));
for (const color of colors) {
console.log(color);
}
// Set from array
const numbers = [1, 2, 2, 3, 3, 4];
const uniqueNumbers2 = new Set(numbers);
const uniqueArray = [...uniqueNumbers2];
console.log(uniqueArray); // [1, 2, 3, 4]
// Set operations
const set1 = new Set([1, 2, 3]);
const set2 = new Set([2, 3, 4]);
// Union
const union = new Set([...set1, ...set2]);
console.log(union); // Set {1, 2, 3, 4}
// Intersection
const intersection = new Set([...set1].filter(x => set2.has(x)));
console.log(intersection); // Set {2, 3}
// Difference
const difference = new Set([...set1].filter(x => !set2.has(x)));
console.log(difference); // Set {1}
// Map - Collection of key-value pairs with any key type
const userMap = new Map();
// Add key-value pairs
userMap.set("name", "John Doe");
userMap.set(1, "User ID 1");
userMap.set({ id: 1 }, "Object key");
userMap.set(true, "Boolean key");
console.log(userMap.get("name")); // "John Doe"
console.log(userMap.get(1)); // "User ID 1"
// Check if key exists
console.log(userMap.has("name")); // true
// Get size
console.log(userMap.size); // 4
// Remove key-value pair
userMap.delete("name");
console.log(userMap.has("name")); // false
// Clear all
userMap.clear();
console.log(userMap.size); // 0
// Map from array of arrays
const userData = [
["name", "John"],
["age", 30],
["city", "NYC"]
];
const userMap2 = new Map(userData);
console.log(userMap2.get("name")); // "John"
// Map iteration
const config = new Map([
["apiUrl", "https://api.example.com"],
["timeout", 5000],
["retries", 3]
]);
// Keys
for (const key of config.keys()) {
console.log(key);
}
// Values
for (const value of config.values()) {
console.log(value);
}
// Entries
for (const [key, value] of config.entries()) {
console.log(`${key}: ${value}`);
}
// forEach
config.forEach((value, key) => {
console.log(`${key} = ${value}`);
});
// Map vs Object
const userObj = {
name: "John",
age: 30
};
const userMap3 = new Map([
["name", "John"],
["age", 30]
]);
// Object keys are always strings
userObj[1] = "one";
console.log(userObj["1"]); // "one"
// Map keys can be any type
userMap3.set(1, "one");
console.log(userMap3.get(1)); // "one"
// WeakSet - Weak reference version of Set
const weakSet = new WeakSet();
const obj1 = { name: "John" };
const obj2 = { name: "Jane" };
weakSet.add(obj1);
weakSet.add(obj2);
console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj2)); // true
// WeakSet limitations
// - Only objects can be added
// - No iteration methods
// - No size property
// - No clear method
// WeakMap - Weak reference version of Map
const weakMap = new WeakMap();
const user1 = { id: 1 };
const user2 = { id: 2 };
weakMap.set(user1, "John Doe");
weakMap.set(user2, "Jane Smith");
console.log(weakMap.get(user1)); // "John Doe"
// WeakMap limitations
// - Only objects can be keys
// - No iteration methods
// - No size property
// - No clear method
// Practical use case: Caching
const cache = new WeakMap();
function expensiveOperation(obj) {
if (cache.has(obj)) {
return cache.get(obj);
}
const result = {
processed: true,
timestamp: Date.now(),
data: obj
};
cache.set(obj, result);
return result;
}
const data1 = { value: "important data" };
const data2 = { value: "more data" };
console.log(expensiveOperation(data1));
console.log(expensiveOperation(data1)); // Returns cached result
console.log(expensiveOperation(data2));
// Exercise: Build a Contact Management System
class ContactManager {
constructor() {
this.contacts = new Map();
this.groups = new Map();
this.tags = new Set();
}
addContact(id, name, email, phone, tags = []) {
const contact = {
id,
name,
email,
phone,
tags: new Set(tags),
createdAt: new Date()
};
this.contacts.set(id, contact);
// Add tags to global tags set
tags.forEach(tag => this.tags.add(tag));
return contact;
}
removeContact(id) {
const contact = this.contacts.get(id);
if (contact) {
this.contacts.delete(id);
return contact;
}
return null;
}
getContact(id) {
return this.contacts.get(id);
}
getAllContacts() {
return Array.from(this.contacts.values());
}
searchContacts(query) {
const results = [];
for (const contact of this.contacts.values()) {
if (contact.name.toLowerCase().includes(query.toLowerCase()) ||
contact.email.toLowerCase().includes(query.toLowerCase())) {
results.push(contact);
}
}
return results;
}
getContactsByTag(tag) {
const results = [];
for (const contact of this.contacts.values()) {
if (contact.tags.has(tag)) {
results.push(contact);
}
}
return results;
}
addGroup(name, contactIds = []) {
const group = new Set(contactIds);
this.groups.set(name, group);
return group;
}
addContactToGroup(contactId, groupName) {
const group = this.groups.get(groupName);
if (group) {
group.add(contactId);
return true;
}
return false;
}
getGroupContacts(groupName) {
const group = this.groups.get(groupName);
if (group) {
return Array.from(group).map(id => this.contacts.get(id)).filter(Boolean);
}
return [];
}
getAllTags() {
return Array.from(this.tags);
}
getStats() {
return {
totalContacts: this.contacts.size,
totalGroups: this.groups.size,
totalTags: this.tags.size
};
}
}
// Test the Contact Manager
const contactManager = new ContactManager();
contactManager.addContact(1, "John Doe", "john@example.com", "555-1234", ["family", "work"]);
contactManager.addContact(2, "Jane Smith", "jane@example.com", "555-5678", ["work"]);
contactManager.addContact(3, "Bob Wilson", "bob@example.com", "555-9012", ["family"]);
console.log("All contacts:", contactManager.getAllContacts().length);
console.log("All tags:", contactManager.getAllTags());
const workContacts = contactManager.getContactsByTag("work");
console.log("Work contacts:", workContacts.length);
contactManager.addGroup("Family", [1, 3]);
const familyGroup = contactManager.getGroupContacts("Family");
console.log("Family group:", familyGroup.length);
console.log("Stats:", contactManager.getStats());
Test your understanding of this topic:
Master JavaScript's prototype-based inheritance system and understand how objects inherit properties and methods
Content by: Shweta Mangukiya
Node.js Developer
JavaScript uses prototype-based inheritance, where objects can inherit properties and methods from other objects through a prototype chain.
// Prototype chain demonstration
const person = {
name: "John",
age: 30,
greet() {
return `Hello, my name is ${this.name}`;
}
};
const student = Object.create(person);
student.study = function() {
return "I'm studying JavaScript";
};
console.log(student.name); // "John" (inherited)
console.log(student.greet()); // "Hello, my name is John" (inherited)
console.log(student.study()); // "I'm studying JavaScript" (own method)
// Prototype chain visualization
console.log(student.__proto__ === person); // true
console.log(person.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null (end of chain)
// Constructor functions and prototypes
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
return `Hello, my name is ${this.name}`;
};
Person.prototype.getAge = function() {
return this.age;
};
const john = new Person("John", 30);
const jane = new Person("Jane", 25);
console.log(john.greet()); // "Hello, my name is John"
console.log(jane.getAge()); // 25
// Prototype inheritance
function Student(name, age, grade) {
Person.call(this, name, age); // Call parent constructor
this.grade = grade;
}
// Set up prototype chain
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.study = function() {
return "I'm studying hard!";
};
const alice = new Student("Alice", 20, "A");
console.log(alice.greet()); // "Hello, my name is Alice"
console.log(alice.study()); // "I'm studying hard!"
console.log(alice.getAge()); // 20
// ES6+ Class inheritance
class Animal {
constructor(name, species) {
this.name = name;
this.species = species;
}
speak() {
return `${this.name} makes a sound`;
}
getInfo() {
return `${this.name} is a ${this.species}`;
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name, "dog"); // Call parent constructor
this.breed = breed;
}
speak() {
return `${this.name} barks: Woof!`;
}
fetch() {
return `${this.name} fetches the ball`;
}
}
class Cat extends Animal {
constructor(name, color) {
super(name, "cat");
this.color = color;
}
speak() {
return `${this.name} meows: Meow!`;
}
purr() {
return `${this.name} purrs contentedly`;
}
}
// Usage
const dog = new Dog("Buddy", "Golden Retriever");
const cat = new Cat("Whiskers", "Orange");
console.log(dog.speak()); // "Buddy barks: Woof!"
console.log(cat.speak()); // "Whiskers meows: Meow!"
console.log(dog.fetch()); // "Buddy fetches the ball"
console.log(cat.purr()); // "Whiskers purrs contentedly"
// Method overriding and super
class Vehicle {
constructor(make, model) {
this.make = make;
this.model = model;
}
start() {
return `${this.make} ${this.model} is starting`;
}
getInfo() {
return `${this.make} ${this.model}`;
}
}
class ElectricCar extends Vehicle {
constructor(make, model, batteryCapacity) {
super(make, model);
this.batteryCapacity = batteryCapacity;
}
start() {
return super.start() + " silently"; // Call parent method
}
getInfo() {
return super.getInfo() + ` with ${this.batteryCapacity}kWh battery`;
}
}
const tesla = new ElectricCar("Tesla", "Model 3", 75);
console.log(tesla.start()); // "Tesla Model 3 is starting silently"
console.log(tesla.getInfo()); // "Tesla Model 3 with 75kWh battery"
// Exercise: Build a Shape Hierarchy
class Shape {
constructor(color) {
this.color = color;
}
getColor() {
return this.color;
}
getArea() {
throw new Error("getArea() must be implemented by subclass");
}
getPerimeter() {
throw new Error("getPerimeter() must be implemented by subclass");
}
getInfo() {
return `A ${this.color} ${this.constructor.name}`;
}
}
class Circle extends Shape {
constructor(color, radius) {
super(color);
this.radius = radius;
}
getArea() {
return Math.PI * this.radius ** 2;
}
getPerimeter() {
return 2 * Math.PI * this.radius;
}
getInfo() {
return super.getInfo() + ` with radius ${this.radius}`;
}
}
class Rectangle extends Shape {
constructor(color, width, height) {
super(color);
this.width = width;
this.height = height;
}
getArea() {
return this.width * this.height;
}
getPerimeter() {
return 2 * (this.width + this.height);
}
getInfo() {
return super.getInfo() + ` with width ${this.width} and height ${this.height}`;
}
}
class Square extends Rectangle {
constructor(color, side) {
super(color, side, side);
this.side = side;
}
getInfo() {
return super.getInfo().replace("Rectangle", "Square").replace(`width ${this.side} and height ${this.side}`, `side ${this.side}`);
}
}
// Test the shape hierarchy
const shapes = [
new Circle("red", 5),
new Rectangle("blue", 4, 6),
new Square("green", 3)
];
shapes.forEach(shape => {
console.log(shape.getInfo());
console.log(`Area: ${shape.getArea().toFixed(2)}`);
console.log(`Perimeter: ${shape.getPerimeter().toFixed(2)}`);
console.log("---");
});
// Challenge: Add more shapes (Triangle, Ellipse, etc.)
// and implement a shape calculator that can work with any shape type
Test your understanding of this topic:
Continue your learning journey and master the next set of concepts.
Continue to Module 5