javascript

exercises

exercises.js
/**
 * ============================================
 * 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 ===');
Exercises - JavaScript Tutorial | DeepML