javascript
examples
examples.js⚡javascript
/**
* ============================================
* 6.2 THE CALL STACK - EXAMPLES
* ============================================
*/
/**
* EXAMPLE 1: Basic Call Stack
* ---------------------------
* Watch functions push and pop from the stack
*/
console.log('=== Example 1: Basic Call Stack ===');
function first() {
console.log('1. Entering first()');
second();
console.log('4. Exiting first()');
}
function second() {
console.log('2. Entering second()');
third();
console.log('3. Exiting second()');
}
function third() {
console.log(' In third() - top of stack!');
}
first();
console.log('5. Back in global scope');
/*
* Stack evolution:
* [Global] → [first, Global] → [second, first, Global]
* → [third, second, first, Global] → [second, first, Global]
* → [first, Global] → [Global]
*/
/**
* EXAMPLE 2: Return Values Through the Stack
* ------------------------------------------
* Values bubble up as functions pop
*/
console.log('\n=== Example 2: Return Values ===');
function addTwo(x) {
console.log(` addTwo(${x}) called`);
return x + 2;
}
function multiplyByThree(x) {
console.log(` multiplyByThree(${x}) called`);
const result = addTwo(x);
return result * 3;
}
function calculate(x) {
console.log(`calculate(${x}) called`);
return multiplyByThree(x);
}
const result = calculate(5);
console.log('Result:', result);
// calculate(5) → multiplyByThree(5) → addTwo(5) → 7
// 7 returns to multiplyByThree → 7 * 3 = 21
// 21 returns to calculate → 21 returns to global
/**
* EXAMPLE 3: Using console.trace()
* --------------------------------
* Built-in way to see the call stack
*/
console.log('\n=== Example 3: console.trace() ===');
function level1() {
level2();
}
function level2() {
level3();
}
function level3() {
console.trace('Call stack at level3:');
}
level1();
/**
* EXAMPLE 4: Stack with Arguments
* -------------------------------
* Each frame has its own arguments
*/
console.log('\n=== Example 4: Stack with Arguments ===');
function greet(greeting) {
console.log(`greet() received: "${greeting}"`);
personalize('Alice');
}
function personalize(name) {
console.log(`personalize() received: "${name}"`);
// Each function has its own arguments
}
greet('Hello');
/**
* EXAMPLE 5: Understanding Stack Overflow
* ---------------------------------------
* Demonstration of what causes overflow
*/
console.log('\n=== Example 5: Stack Overflow Demo ===');
// This would cause stack overflow - DON'T UNCOMMENT!
// function infiniteRecursion() {
// infiniteRecursion();
// }
// infiniteRecursion();
// Safe demonstration - counting recursion depth
let depth = 0;
function measureStackDepth() {
depth++;
try {
measureStackDepth();
} catch (e) {
// Stack overflow caught
}
}
measureStackDepth();
console.log(`Approximate stack depth limit: ${depth}`);
/**
* EXAMPLE 6: Proper Recursion with Base Case
* ------------------------------------------
* Recursion that doesn't overflow
*/
console.log('\n=== Example 6: Proper Recursion ===');
function countdown(n) {
console.log(` countdown(${n})`);
// Base case - stops the recursion
if (n <= 0) {
console.log(' Blast off! 🚀');
return;
}
// Recursive case
countdown(n - 1);
}
countdown(5);
/**
* EXAMPLE 7: Stack Trace from Error
* ---------------------------------
* Reading error stack traces
*/
console.log('\n=== Example 7: Error Stack Trace ===');
function controller() {
service();
}
function service() {
repository();
}
function repository() {
database();
}
function database() {
// Simulate an error
throw new Error('Connection failed!');
}
try {
controller();
} catch (e) {
console.log('Error caught!');
console.log('Stack trace:');
console.log(e.stack);
}
/**
* EXAMPLE 8: Multiple Call Stacks (Sort of)
* -----------------------------------------
* Each call creates a new stack frame, even for the same function
*/
console.log('\n=== Example 8: Same Function, Different Frames ===');
function process(id) {
console.log(`Processing ${id}`);
if (id < 3) {
process(id + 1);
}
console.log(`Finished ${id}`);
}
process(1);
// Each call to process() is a separate frame on the stack
/**
* EXAMPLE 9: Blocking the Call Stack
* -----------------------------------
* Demonstration of stack blocking
*/
console.log('\n=== Example 9: Blocking Demo ===');
function quickOperation() {
console.log('Quick operation done');
}
function slowOperation() {
console.log('Starting slow operation...');
// This blocks - DON'T do this in real code!
const start = Date.now();
while (Date.now() - start < 100) {
// Busy waiting
}
console.log('Slow operation done (blocked for 100ms)');
}
console.log('Before slow operation');
slowOperation();
quickOperation(); // Has to wait for slowOperation
console.log('After all operations');
/**
* EXAMPLE 10: Non-Blocking Alternative
* ------------------------------------
* Using async patterns to avoid blocking
*/
console.log('\n=== Example 10: Non-Blocking ===');
function asyncOperation(callback) {
console.log('Starting async operation...');
// This doesn't block - callback goes to task queue
setTimeout(() => {
console.log('Async operation completed!');
callback();
}, 100);
console.log('Async operation scheduled (not blocking)');
}
console.log('Before async operation');
asyncOperation(() => console.log('Callback executed'));
console.log('After starting async operation');
// Note the order of outputs!
/**
* EXAMPLE 11: LIFO Demonstrated
* -----------------------------
* Last In, First Out behavior
*/
console.log('\n=== Example 11: LIFO Behavior ===');
function a() {
console.log('a() starting');
b();
console.log('a() ending - was waiting for b()');
}
function b() {
console.log(' b() starting');
c();
console.log(' b() ending - was waiting for c()');
}
function c() {
console.log(' c() executing - top of stack');
// c() finishes first (Last In, First Out)
}
a();
/**
* EXAMPLE 12: Visualizing with Custom Stack
* -----------------------------------------
* Manual stack simulation
*/
console.log('\n=== Example 12: Manual Stack Visualization ===');
const callStack = [];
function pushToStack(name) {
callStack.push(name);
console.log(`PUSH: ${name}`);
console.log(`Stack: [${callStack.join(', ')}]`);
}
function popFromStack() {
const name = callStack.pop();
console.log(`POP: ${name}`);
console.log(`Stack: [${callStack.join(', ')}]`);
return name;
}
pushToStack('global');
pushToStack('funcA');
pushToStack('funcB');
pushToStack('funcC');
popFromStack();
popFromStack();
popFromStack();
popFromStack();
/**
* EXAMPLE 13: Factorial with Stack Visualization
* -----------------------------------------------
* See how recursion uses the stack
*/
console.log('\n=== Example 13: Factorial Stack ===');
function factorialVerbose(n, indent = '') {
console.log(`${indent}factorial(${n}) called`);
if (n <= 1) {
console.log(`${indent}Base case: returning 1`);
return 1;
}
const result = n * factorialVerbose(n - 1, indent + ' ');
console.log(`${indent}factorial(${n}) returning ${result}`);
return result;
}
console.log('Result:', factorialVerbose(5));
/**
* EXAMPLE 14: Mutual Recursion
* ----------------------------
* Two functions calling each other
*/
console.log('\n=== Example 14: Mutual Recursion ===');
function isEven(n) {
if (n === 0) return true;
return isOdd(n - 1);
}
function isOdd(n) {
if (n === 0) return false;
return isEven(n - 1);
}
console.log('isEven(4):', isEven(4)); // true
console.log('isOdd(5):', isOdd(5)); // true
// Stack for isEven(4):
// isEven(4) → isOdd(3) → isEven(2) → isOdd(1) → isEven(0) → true
/**
* EXAMPLE 15: Stack and Event Loop Interaction
* --------------------------------------------
* How async code interacts with the stack
*/
console.log('\n=== Example 15: Stack and Event Loop ===');
function syncTask() {
console.log('2. Sync task executing (in stack)');
}
function asyncTask() {
console.log('4. Async task executing (from queue)');
}
console.log('1. Start (in stack)');
// This goes to the task queue, not the stack
setTimeout(asyncTask, 0);
syncTask();
console.log('3. End (in stack)');
// Output order: 1, 2, 3, 4
// Async task waits for stack to be empty
/**
* EXAMPLE 16: Creating a Stack Trace Manually
* -------------------------------------------
* How to capture and use stack information
*/
console.log('\n=== Example 16: Manual Stack Trace ===');
function captureStack() {
const stack = new Error().stack;
return stack.split('\n').slice(1).join('\n');
}
function innerFunction() {
console.log('Stack at innerFunction:');
console.log(captureStack());
}
function middleFunction() {
innerFunction();
}
function outerFunction() {
middleFunction();
}
outerFunction();
/**
* EXAMPLE 17: Stack with Try-Catch
* --------------------------------
* Error handling and the stack
*/
console.log('\n=== Example 17: Try-Catch and Stack ===');
function layer3() {
throw new Error('Error at layer 3');
}
function layer2() {
layer3();
}
function layer1() {
try {
layer2();
} catch (e) {
console.log('Caught at layer1!');
console.log('Error originated at:', e.stack.split('\n')[1].trim());
}
}
layer1();
/**
* EXAMPLE 18: Performance Considerations
* --------------------------------------
* Deep stacks have overhead
*/
console.log('\n=== Example 18: Performance ===');
// Iterative (constant stack space)
function sumIterative(n) {
let total = 0;
for (let i = 1; i <= n; i++) {
total += i;
}
return total;
}
// Recursive (O(n) stack space)
function sumRecursive(n) {
if (n <= 0) return 0;
return n + sumRecursive(n - 1);
}
console.time('Iterative');
console.log('Iterative sum(1000):', sumIterative(1000));
console.timeEnd('Iterative');
console.time('Recursive');
console.log('Recursive sum(1000):', sumRecursive(1000));
console.timeEnd('Recursive');
console.log('\n=== End of Examples ===');