✅ Answers & Explanations to All 8 Questions
🧠 1. Closure Puzzle with var and let
const funcs = [];
for (var i = 0; i < 3; i++) {
funcs.push(() => console.log(i)); // closure over `i`
}
for (let i = 0; i < 3; i++) {
funcs.push(() => console.log(i)); // block scoped `i`
}
funcs.forEach(fn => fn());
✅ Output:
3
3
3
0
1
2
💡 Why:
● var is function scoped, so all 3 closures share the same i, which becomes 3 after the
loop.
● let is block scoped, so each iteration gets its own i — captured correctly as 0, 1, 2.
🔥 2. Temporal Dead Zone with Hoisting
function test() {
console.log(a); // ❌ ReferenceError
let a = 10;
}
test();
✅ Output:
pgsql
ReferenceError: Cannot access 'a' before initialization
💡 Why:
● let is hoisted but exists in a temporal dead zone (TDZ).
● Accessing a before initialization throws a ReferenceError — not undefined like var.
🕳️ 3. Deep Destructuring & Reference Mutation
const user = { info: { name: "Alice", age: 25 } };
const { info } = user;
info.age = 30;
console.log(user.info.age); // ?
✅ Output:
30
💡 Why:
● Destructuring { info } copies the reference — not a deep clone.
● So info.age = 30 mutates the same info object inside user.
⏳ 4. Event Loop Madness
console.log('A');
setTimeout(() => console.log('B'), 0);
Promise.resolve().then(() => console.log('C'));
console.log('D');
✅ Output:
css
A
D
C
B
💡 Why:
● 'A' and 'D' are synchronous, logged immediately.
● Promise.then(...) is a microtask, runs after sync but before macrotasks.
● setTimeout(..., 0) is a macrotask, runs after microtasks.
🧪 5. Function Binding and Context Loss
const obj = {
value: 42,
getValue: function() {
return this.value;
}
};
const fn = obj.getValue;
console.log(fn()); // ?
✅ Output:
vbnet
undefined (or error in strict mode)
💡 Why:
● fn is called without a context — this becomes window (or undefined in strict mode).
● To fix:
const fn = obj.getValue.bind(obj);
⚙️ 6. Object Property Gotcha
const a = { name: "test" };
const b = { name: "test" };
const map = new Map();
map.set(a, 123);
map.set(b, 456);
console.log(map.get({ name: "test" }));
✅ Output:
javascript
undefined
💡 Why:
● { name: "test" } is a new object. Map keys are compared by reference, not by
value.
● So the final .get() doesn’t match any key.
💥 7. Class Inheritance: Overriding Pitfall
class Parent {
constructor() {
this.say = () => console.log('Parent');
}
}
class Child extends Parent {
constructor() {
super();
this.say = () => console.log('Child');
}
}
const p = new Parent();
const c = new Child();
p.say(); // ?
c.say(); // ?
✅ Output:
nginx
Parent
Child
💡 Why:
● Each say is a new arrow function on the instance.
● If say was defined on the prototype instead, it could be overridden without reassigning
in constructor.
🧩 8. Recursive Promise Trap
const fn = () => Promise.resolve().then(() => fn());
fn();
✅ Output:
arduino
Infinite loop of microtasks, eventually causes stack overflow or
memory exhaustion.
💡 Why:
● This is a recursive chain of promises — no base case = infinite recursion via
microtasks.
● Even though it’s async, it never breaks the loop, and will blow up memory.
● ⚠️ Dangerous pattern! Always add a stopping condition.