Let's think this through for a moment
This practice set combines concepts from the Advanced Concepts, OOP, and Async JavaScript chapters — closures, arrow functions, destructuring, classes, and promises/async-await — into tougher, more real-world-like scenarios. It's a step up from Exercise 1: instead of testing one concept at a time, these tasks make you combine two concepts together (for example, closures + higher-order functions). Try spending 10-15 minutes thinking it through yourself before checking the solution. Harder challenges like these are also great practice for interview prep.
Exercises
Task 1: Using a closure, write a `createCounter()` factory function that returns an object with `increment()`, `decrement()`, and `reset()` methods — the internal count variable should not be directly accessible from outside. Task 2: Build a `Person` class whose constructor takes name and age, and add a static method `compareAge(p1, p2)` that returns whichever person is older. Task 3: Write an async function called `fetchUserData(id)` (simulate the promise with `setTimeout`) and use async/await with try/catch to handle errors. Task 4: Using destructuring and the spread operator on an array of objects, chain `map()` and `filter()` together to pull out just the names of items priced under 1000 as an array.
Code Example
// Task 1: Closure counter factory
function createCounter() {
let count = 0;
return {
increment: () => ++count,
decrement: () => --count,
reset: () => (count = 0)
};
}
// Task 2: Person class with static method
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
static compareAge(p1, p2) {
// TODO: age ကြီးတဲ့ Person object ကို ပြန်ပေးပါ
}
}
// Task 3: Async/await with error handling
function fetchUserData(id) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (id <= 0) reject(new Error("Invalid user id"));
else resolve({ id, name: "User " + id });
}, 500);
});
}
async function loadUser(id) {
try {
const user = await fetchUserData(id);
console.log(user);
} catch (err) {
// TODO: error ကို handle လုပ်ပါ
}
}
// Task 4: destructuring + map/filter chain
const products = [
{ name: "Pen", price: 500 },
{ name: "Bag", price: 15000 },
{ name: "Book", price: 800 }
];
const cheapNames = products
.filter(({ price }) => price < 1000)
.map(({ name }) => name);
console.log(cheapNames);You should get the increment/decrement/reset results from the Counter object, the older Person object from `compareAge`, the user data (or a caught error message) from `loadUser(id)`, and a `["Pen", "Book"]` array for `cheapNames`.Try it for 5 minutes
Take 5 minutes to call Task 3's function with `loadUser(-1)` and check whether the error path is handled properly.
A quick word of caution
Try rewriting Task 3 using `.then().catch()` instead of async/await, and compare the readability of both versions yourself — this kind of comparison is a genuinely useful debugging skill for real projects.