javascript
exercises
exercises.js⚡javascript
/**
* ============================================
* 6.1 EXECUTION CONTEXT - EXERCISES
* ============================================
*
* Practice understanding execution contexts,
* the creation phase, and the execution phase.
*/
/**
* EXERCISE 1: Predict the Output
* ------------------------------
* Without running the code, predict what will be logged.
* Then run it to check your answer.
*/
console.log('=== Exercise 1: Predict the Output ===');
console.log(a);
var a = 5;
console.log(a);
// YOUR PREDICTION:
// First console.log outputs: ___
// Second console.log outputs: ___
/*
* SOLUTION:
* First console.log outputs: undefined
* Second console.log outputs: 5
*
* Explanation:
* - Creation phase: 'a' is hoisted and set to undefined
* - Execution phase: First log runs (a is undefined)
* - Then a = 5 is assigned
* - Second log runs (a is now 5)
*/
/**
* EXERCISE 2: Function Hoisting
* -----------------------------
* Predict the output and explain why.
*/
console.log('\n=== Exercise 2: Function Hoisting ===');
function exercise2() {
console.log(typeof foo);
console.log(typeof bar);
var foo = 'foo value';
function bar() {
return 'bar function';
}
console.log(typeof foo);
console.log(typeof bar);
}
exercise2();
// YOUR PREDICTION:
// Line 1 (typeof foo): ___
// Line 2 (typeof bar): ___
// Line 3 (typeof foo): ___
// Line 4 (typeof bar): ___
/*
* SOLUTION:
* Line 1: "undefined" (var hoisted, value not assigned yet)
* Line 2: "function" (function declarations fully hoisted)
* Line 3: "string" (foo now has its value)
* Line 4: "function" (still a function)
*/
/**
* EXERCISE 3: Scope Chain
* -----------------------
* Predict the output of each console.log.
*/
console.log('\n=== Exercise 3: Scope Chain ===');
var x = 10;
function outer() {
var x = 20;
function inner() {
var x = 30;
console.log('inner x:', x);
}
inner();
console.log('outer x:', x);
}
outer();
console.log('global x:', x);
// YOUR PREDICTION:
// inner x: ___
// outer x: ___
// global x: ___
/*
* SOLUTION:
* inner x: 30
* outer x: 20
* global x: 10
*
* Each function has its own 'x' in its execution context.
*/
/**
* EXERCISE 4: Missing Variable
* ----------------------------
* Predict what happens at each console.log.
*/
console.log('\n=== Exercise 4: Missing Variable ===');
var y = 100;
function exercise4() {
console.log('y inside function:', y);
function inner() {
console.log('y in inner:', y);
}
inner();
}
exercise4();
// YOUR PREDICTION:
// y inside function: ___
// y in inner: ___
/*
* SOLUTION:
* y inside function: 100
* y in inner: 100
*
* When 'y' isn't found locally, JavaScript looks up the scope chain.
*/
/**
* EXERCISE 5: Shadowing
* ---------------------
* Explain why the outputs differ.
*/
console.log('\n=== Exercise 5: Shadowing ===');
var name = 'Global';
function greetGlobal() {
console.log('Hello, ' + name);
}
function greetLocal() {
var name = 'Local';
console.log('Hello, ' + name);
}
function greetWithParameter(name) {
console.log('Hello, ' + name);
}
greetGlobal();
greetLocal();
greetWithParameter('Parameter');
// YOUR PREDICTION:
// greetGlobal(): Hello, ___
// greetLocal(): Hello, ___
// greetWithParameter("Parameter"): Hello, ___
/*
* SOLUTION:
* greetGlobal(): Hello, Global
* greetLocal(): Hello, Local
* greetWithParameter("Parameter"): Hello, Parameter
*
* Local variables and parameters "shadow" outer variables.
*/
/**
* EXERCISE 6: TDZ (Temporal Dead Zone)
* ------------------------------------
* Predict which lines will throw errors.
*/
console.log('\n=== Exercise 6: TDZ ===');
function exercise6() {
// Uncomment each line one at a time to test
// Line A:
// console.log(varVariable); // What happens?
var varVariable = 'var';
// Line B:
// console.log(letVariable); // What happens?
let letVariable = 'let';
// Line C:
// console.log(constVariable); // What happens?
const constVariable = 'const';
console.log('All variables:', varVariable, letVariable, constVariable);
}
exercise6();
// YOUR PREDICTION:
// Line A throws error? ___
// Line B throws error? ___
// Line C throws error? ___
/*
* SOLUTION:
* Line A: No error - logs "undefined" (var is hoisted)
* Line B: ReferenceError - let is in TDZ
* Line C: ReferenceError - const is in TDZ
*/
/**
* EXERCISE 7: Creation Phase Quiz
* -------------------------------
* Write what the execution context looks like after the creation phase.
*/
console.log('\n=== Exercise 7: Creation Phase Quiz ===');
function quiz(param) {
var local = 'local value';
function nested() {}
var another;
}
// quiz(42);
// Write the creation phase state:
/*
* YOUR ANSWER:
* {
* arguments: ___,
* param: ___,
* local: ___,
* nested: ___,
* another: ___,
* this: ___
* }
*/
/*
* SOLUTION:
* {
* arguments: { 0: 42, length: 1 },
* param: 42,
* local: undefined,
* nested: function nested() {},
* another: undefined,
* this: global object (or undefined in strict mode)
* }
*/
/**
* EXERCISE 8: Multiple Calls
* --------------------------
* Trace the execution contexts created.
*/
console.log('\n=== Exercise 8: Multiple Calls ===');
var counter = 0;
function increment() {
counter++;
console.log('Counter:', counter);
}
increment();
increment();
increment();
// Question: How many Function Execution Contexts were created total?
// YOUR ANSWER: ___
/*
* SOLUTION: 3 Function Execution Contexts
*
* Each call to increment() creates a new FEC.
* They all share the same global 'counter' variable.
*/
/**
* EXERCISE 9: Identify the Bug
* ----------------------------
* Why doesn't this work as expected?
*/
console.log('\n=== Exercise 9: Identify the Bug ===');
function createFunctions() {
var result = [];
for (var i = 0; i < 3; i++) {
result.push(function () {
console.log('Value:', i);
});
}
return result;
}
var funcs = createFunctions();
funcs[0](); // Expected: 0
funcs[1](); // Expected: 1
funcs[2](); // Expected: 2
// Question: What actually gets logged? Why?
// YOUR ANSWER: ___
// Fix the bug (write your solution):
function createFunctionsFixed() {
var result = [];
// YOUR CODE HERE
return result;
}
/*
* SOLUTION:
* All three log "Value: 3"
*
* Why: 'var i' creates ONE variable in the function's context.
* All closures reference the SAME 'i', which is 3 after the loop.
*
* Fix using let:
*/
function createFunctionsFixed() {
var result = [];
for (let i = 0; i < 3; i++) {
result.push(function () {
console.log('Value:', i);
});
}
return result;
}
/**
* EXERCISE 10: 'this' in Execution Context
* ----------------------------------------
* Predict the value of 'this' in each case.
*/
console.log("\n=== Exercise 10: 'this' Binding ===");
const person = {
name: 'Alice',
sayName: function () {
console.log("sayName 'this'.name:", this.name);
},
sayNameArrow: () => {
console.log("sayNameArrow 'this':", this);
},
delayed: function () {
setTimeout(function () {
console.log("setTimeout callback 'this':", this);
}, 0);
},
delayedArrow: function () {
setTimeout(() => {
console.log("setTimeout arrow 'this'.name:", this.name);
}, 0);
},
};
person.sayName();
person.sayNameArrow();
// person.delayed(); // Uncomment to test
// person.delayedArrow(); // Uncomment to test
// YOUR PREDICTIONS:
// sayName 'this'.name: ___
// sayNameArrow 'this': ___
// setTimeout callback 'this': ___
// setTimeout arrow 'this'.name: ___
/*
* SOLUTION:
* sayName 'this'.name: "Alice" (method call, this = person)
* sayNameArrow 'this': global object (arrow inherits outer 'this')
* setTimeout callback 'this': global/undefined (regular function in setTimeout)
* setTimeout arrow 'this'.name: "Alice" (arrow preserves outer 'this')
*/
/**
* EXERCISE 11: Build an Execution Context
* ---------------------------------------
* Manually trace through this code and build the execution contexts.
*/
console.log('\n=== Exercise 11: Build Execution Context ===');
var color = 'blue';
function changeColor(newColor) {
var color = newColor;
function verify() {
return color;
}
return verify();
}
var result = changeColor('red');
console.log(result);
// Draw the execution contexts:
/*
* Global EC:
* - color: ___
* - changeColor: ___
* - result: ___
*
* changeColor("red") EC:
* - arguments: ___
* - newColor: ___
* - color: ___
* - verify: ___
*
* verify() EC:
* - (empty, uses outer scope)
*/
/*
* SOLUTION:
* Global EC:
* - color: "blue"
* - changeColor: function
* - result: "red" (after changeColor returns)
*
* changeColor("red") EC:
* - arguments: { 0: "red", length: 1 }
* - newColor: "red"
* - color: "red"
* - verify: function
*
* verify() EC:
* - arguments: { length: 0 }
* - Looks up scope chain, finds color = "red"
*/
/**
* EXERCISE 12: Strict Mode Differences
* ------------------------------------
* Predict the behavior in strict vs non-strict mode.
*/
console.log('\n=== Exercise 12: Strict Mode ===');
function nonStrictTest() {
return typeof this;
}
function strictTest() {
'use strict';
return typeof this;
}
console.log('Non-strict function called directly:', nonStrictTest());
console.log('Strict function called directly:', strictTest());
// YOUR PREDICTION:
// Non-strict: ___
// Strict: ___
/*
* SOLUTION:
* Non-strict: "object" (this is global object)
* Strict: "undefined" (this is undefined in strict mode)
*/
/**
* EXERCISE 13: Hoisting Order
* ---------------------------
* What gets logged and why?
*/
console.log('\n=== Exercise 13: Hoisting Order ===');
function hoistOrder() {
console.log(typeof value);
var value = "I'm a string";
function value() {
return "I'm a function";
}
console.log(typeof value);
}
hoistOrder();
// YOUR PREDICTION:
// First typeof: ___
// Second typeof: ___
/*
* SOLUTION:
* First typeof: "function"
* Second typeof: "string"
*
* Explanation:
* - During creation phase, function declarations are hoisted first
* - Then var declarations (but 'value' already exists, so ignored)
* - During execution, var value = "string" overwrites the function
*/
/**
* EXERCISE 14: Scope Chain Lookup
* -------------------------------
* Trace how the scope chain finds each variable.
*/
console.log('\n=== Exercise 14: Scope Chain Lookup ===');
var a = 1;
function first() {
var b = 2;
function second() {
var c = 3;
function third() {
var d = 4;
console.log(a, b, c, d);
}
third();
}
second();
}
first();
// Trace for each variable in third():
// - d is found in: ___
// - c is found in: ___
// - b is found in: ___
// - a is found in: ___
/*
* SOLUTION:
* - d is found in: third()'s own scope
* - c is found in: second()'s scope (1 level up)
* - b is found in: first()'s scope (2 levels up)
* - a is found in: global scope (3 levels up)
*/
/**
* EXERCISE 15: Create Isolated Contexts
* -------------------------------------
* Use IIFEs to create separate execution contexts with the same variable names.
*/
console.log('\n=== Exercise 15: Create Isolated Contexts ===');
// Create three IIFEs, each with their own 'secret' variable
// that logs different values
// YOUR CODE HERE:
/*
(function() {
var secret = ???;
console.log(secret);
})();
(function() {
var secret = ???;
console.log(secret);
})();
(function() {
var secret = ???;
console.log(secret);
})();
*/
/*
* SOLUTION:
*/
(function () {
var secret = 'First secret';
console.log(secret);
})();
(function () {
var secret = 'Second secret';
console.log(secret);
})();
(function () {
var secret = 'Third secret';
console.log(secret);
})();
// Each IIFE has its own execution context with its own 'secret'
console.log('\n=== Exercises Complete ===');
console.log('Review your answers against the solutions!');