javascript
exercises
exercises.js⚡javascript
/**
* ============================================
* 6.3 HOISTING DEEP DIVE - EXERCISES
* ============================================
*
* Practice predicting hoisting behavior and
* understanding the Temporal Dead Zone.
*/
/**
* EXERCISE 1: Basic var Hoisting
* ------------------------------
* Predict the output before running.
*/
console.log('=== Exercise 1: Basic var Hoisting ===');
console.log(a);
var a = 5;
console.log(a);
// YOUR PREDICTION:
// First console.log: ___
// Second console.log: ___
/*
* SOLUTION:
* First: undefined (var is hoisted, value is not)
* Second: 5 (after assignment)
*/
/**
* EXERCISE 2: Function Declaration
* --------------------------------
* Will this work? Why?
*/
console.log('\n=== Exercise 2: Function Declaration ===');
console.log(add(2, 3));
function add(a, b) {
return a + b;
}
// YOUR PREDICTION: ___
/*
* SOLUTION:
* Output: 5
* Function declarations are fully hoisted (name + body)
*/
/**
* EXERCISE 3: Function Expression
* -------------------------------
* Will this work? Why?
*/
console.log('\n=== Exercise 3: Function Expression ===');
try {
console.log(multiply(2, 3));
} catch (e) {
console.log('Error:', e.message);
}
var multiply = function (a, b) {
return a * b;
};
// YOUR PREDICTION: ___
/*
* SOLUTION:
* Error: multiply is not a function
* Only var declaration is hoisted (as undefined), not the function
*/
/**
* EXERCISE 4: let vs var
* ----------------------
* What's the difference in behavior?
*/
console.log('\n=== Exercise 4: let vs var ===');
function testVar() {
console.log('var x:', x);
var x = 10;
}
function testLet() {
// console.log("let y:", y); // Uncomment to test
let y = 10;
console.log('let y:', y);
}
testVar();
testLet();
// YOUR PREDICTION:
// testVar output: ___
// testLet output (with console.log uncommented): ___
/*
* SOLUTION:
* testVar: "var x: undefined"
* testLet: ReferenceError (let is in TDZ until declaration)
*/
/**
* EXERCISE 5: Same Name - Function vs Variable
* ---------------------------------------------
* What gets logged and why?
*/
console.log('\n=== Exercise 5: Name Conflict ===');
console.log('Step 1:', typeof thing);
var thing = 'I am a string';
function thing() {
return 'I am a function';
}
console.log('Step 2:', typeof thing);
// YOUR PREDICTION:
// Step 1: ___
// Step 2: ___
/*
* SOLUTION:
* Step 1: "function" (function hoisted first, var ignored)
* Step 2: "string" (assignment overwrites function)
*/
/**
* EXERCISE 6: Nested Function Hoisting
* ------------------------------------
* Trace the hoisting behavior.
*/
console.log('\n=== Exercise 6: Nested Function Hoisting ===');
function outer() {
console.log('inner1:', typeof inner);
inner(); // Will this work?
function inner() {
console.log('inner function called');
}
}
outer();
// YOUR PREDICTION: ___
/*
* SOLUTION:
* inner1: "function"
* inner function called
*
* Function declaration is fully hoisted within outer's scope
*/
/**
* EXERCISE 7: var in Conditional
* ------------------------------
* Is hoisted variable accessible?
*/
console.log('\n=== Exercise 7: var in Conditional ===');
function conditional() {
console.log('value:', value);
if (false) {
var value = 'never executed';
}
console.log('value after:', value);
}
conditional();
// YOUR PREDICTION:
// First log: ___
// Second log: ___
/*
* SOLUTION:
* First: undefined (var is hoisted even from unexecuted block)
* Second: undefined (assignment never runs)
*/
/**
* EXERCISE 8: TDZ in Practice
* ---------------------------
* Identify where TDZ causes errors.
*/
console.log('\n=== Exercise 8: TDZ Practice ===');
function tdzTest() {
// Line A: const before = x; // Error?
// Line B:
const x = 10;
// Line C:
const after = x;
console.log('after:', after);
}
tdzTest();
// YOUR PREDICTION:
// Line A would cause: ___
// Line C works because: ___
/*
* SOLUTION:
* Line A: ReferenceError (x is in TDZ)
* Line C: Works because x has been initialized (TDZ ended at Line B)
*/
/**
* EXERCISE 9: Loop Hoisting Problem
* ---------------------------------
* Explain why this doesn't work as expected.
*/
console.log('\n=== Exercise 9: Loop Hoisting ===');
var functions = [];
for (var i = 0; i < 3; i++) {
functions.push(function () {
return i;
});
}
console.log(
'Results:',
functions.map((f) => f())
);
// YOUR PREDICTION: ___
// EXPLANATION: ___
/*
* SOLUTION:
* Results: [3, 3, 3]
*
* var i is hoisted to function scope, creating ONE variable.
* All closures reference the SAME i, which is 3 after the loop.
*
* Fix: use let instead of var
*/
/**
* EXERCISE 10: Fix the Loop
* -------------------------
* Rewrite Exercise 9 to output [0, 1, 2].
*/
console.log('\n=== Exercise 10: Fix the Loop ===');
// YOUR CODE HERE:
var fixedFunctions = [];
// for ...
/*
* SOLUTION:
*/
for (let j = 0; j < 3; j++) {
fixedFunctions.push(function () {
return j;
});
}
console.log(
'Fixed results:',
fixedFunctions.map((f) => f())
);
/**
* EXERCISE 11: Class Hoisting
* ---------------------------
* Will this work?
*/
console.log('\n=== Exercise 11: Class Hoisting ===');
try {
const instance = new Animal('Cat');
console.log(instance.name);
} catch (e) {
console.log('Error:', e.message);
}
class Animal {
constructor(name) {
this.name = name;
}
}
// YOUR PREDICTION: ___
/*
* SOLUTION:
* Error: Cannot access 'Animal' before initialization
* Classes are hoisted but remain in TDZ (like let/const)
*/
/**
* EXERCISE 12: Multiple Declarations
* -----------------------------------
* What happens with multiple var declarations?
*/
console.log('\n=== Exercise 12: Multiple var ===');
var x = 1;
var x = 2;
var x;
console.log('x:', x);
// YOUR PREDICTION: ___
/*
* SOLUTION:
* x: 2
*
* Re-declaring with var is allowed (just ignored if no assignment).
* The last assignment (x = 2) is what sticks.
*/
/**
* EXERCISE 13: Shadowing with Hoisting
* ------------------------------------
* Trace the values carefully.
*/
console.log('\n=== Exercise 13: Shadowing ===');
var name = 'global';
function shadow() {
console.log('A:', name);
var name = 'local';
console.log('B:', name);
}
shadow();
console.log('C:', name);
// YOUR PREDICTION:
// A: ___
// B: ___
// C: ___
/*
* SOLUTION:
* A: undefined (local 'name' is hoisted, shadows global)
* B: "local" (after local assignment)
* C: "global" (global is unchanged)
*/
/**
* EXERCISE 14: Function and Arrow Comparison
* ------------------------------------------
* Predict which work and which fail.
*/
console.log('\n=== Exercise 14: Function Types ===');
// Test 1
try {
console.log('funcDecl:', funcDecl());
} catch (e) {
console.log('funcDecl error:', e.message);
}
function funcDecl() {
return 'declaration';
}
// Test 2
try {
console.log('funcExpr:', funcExpr());
} catch (e) {
console.log('funcExpr error:', e.message);
}
var funcExpr = function () {
return 'expression';
};
// Test 3
try {
console.log('arrowFunc:', arrowFunc());
} catch (e) {
console.log('arrowFunc error:', e.message);
}
const arrowFunc = () => 'arrow';
// YOUR PREDICTIONS:
// Test 1: ___
// Test 2: ___
// Test 3: ___
/*
* SOLUTION:
* Test 1: "declaration" (function declarations are fully hoisted)
* Test 2: error - funcExpr is not a function
* Test 3: error - Cannot access 'arrowFunc' before initialization
*/
/**
* EXERCISE 15: Write Hoisting-Safe Code
* -------------------------------------
* Rewrite this code to be clear and hoisting-safe.
*/
console.log('\n=== Exercise 15: Write Safe Code ===');
// ORIGINAL (confusing):
function confusingCode() {
console.log(result);
doWork();
var result = data * 2;
function doWork() {
data = 5;
}
var data;
return result;
}
// YOUR REWRITE (clear and safe):
function clearCode() {
// YOUR CODE HERE
}
/*
* SOLUTION:
*/
function clearCodeSolution() {
// Declare all variables at the top
let data;
let result;
// Define functions before use
function doWork() {
data = 5;
}
// Execute logic
doWork();
result = data * 2;
console.log('Result:', result);
return result;
}
clearCodeSolution();
console.log('\n=== Exercises Complete ===');