JavaScript Fundamentals : Exercises

πŸ“š Table of Contents:

πŸ” Closures

function outer() {
  let count = 0;
  return function inner() {
    count++;
    return count;
  };
}

const createCounter = outer();
console.log(createCounter()); // 1
console.log(createCounter()); // 2

✅ inner() still has access to variable count, even though outer() has finished running.

πŸ”Ήvar declaration in loops inside Closures

for (var i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Prints 3, 3, 3
✅ Use let to avoid this:
for (let i = 0; i < 3; i++) {
  setTimeout(() => console.log(i), 100);
}
// Prints 0, 1, 2

 πŸ” Hoisting

πŸ”Ήvar Hoisting

console.log(x); // undefined
var x = 5;
Actual Flow:
var x;           // Declaration hoisted
console.log(x);  // undefined

x = 5;           // Assignment happens later


πŸ”Ήlet and const Hoisting

console.log(y); // ❌ ReferenceError
let y = 10;

πŸ”ΉFunction Declarations Hoisting

sayHi(); // ✅ Works
function sayHi() {
  console.log("Hi!");
}
 
Hoisted completely — both declaration and definition
πŸ”ΉFunction Expressions Hoisting

sayHi(); // ❌ TypeError
var sayHi = function () {
  console.log("Hi!");
}; 
Only declaration hoisted - considered as variable

 πŸ” Scoping

πŸ”Ήvar, let & const

let z = 4;// Global Scope
function test() {
var x = 3; // Function Scope
 
  if (true) {
    var x = 1; // Function Scope
    let y = 2; // Block Scope
  }
  console.log(x); // 1
  console.log(y); //❌ ReferenceError 
}

console.log(z); // 4  

πŸ” Promises

const fetchData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('Data loaded');
    }, 1000);
  });
};

fetchData().then((data) => console.log(data)).catch((error) => console.log(error);

πŸ” Async/Await

async function loadData() {
  console.log('Fetching...');
  const data = await fetchData(); //pauses
  console.log(data);
}

πŸ” Event Loop

console.log("Start");
setTimeout(() => {
  console.log("Macrotask");
}, 0);

Promise.resolve().then(() => {
  console.log("Microtask");
});

console.log("End");
order of execution
// Start
// End 
// Microtask 
// Macrotask

πŸ” this

const user = {
  name: 'User1',
  sayHi() {
    setTimeout(function () {
      console.log(`Hi, I'm ${this.name}`);
    }, 1000);
  }
};

user.sayHi(); // ❌ undefined

 

✅ Fix it with bind:
setTimeout(function () {
  console.log(`Hi, I'm ${this.name}`); // Hi, I'm User1
}.bind(this), 1000);
✅ Or use an arrow function:
setTimeout(() => {
  console.log(`Hi, I'm ${this.name}`); // Hi, I'm User1
}, 1000);

Arrow functions don’t bind their own this—they inherit it from the outer context.

πŸ” call, apply & bind

function greet(city) {
  console.log(`Hi, I'm ${this.name} from ${city}`);
}
const person = { name: 'User1' };
πŸ”„ Using call
greet.call(person, 'Berlin'); // "Hi, I'm User1 from Berlin"
πŸ”„ Using apply
greet.apply(person, ['Berlin']); // "Hi, I'm User1 from Berlin"
πŸ”„ Using bind
const boundGreet = greet.bind(person, 'Berlin');
boundGreet(); // "Hi, I'm User1 from Berlin"

πŸ” stack, heap, GC

    let heapObject = null;
    function simulateStackHeap() {
      // === Stack Allocation (local variables) ===
      const number = 42;                 // Primitive → stack
      const message = "Hello, stack!";   // Primitive → stack

// === Heap Allocation ===   
heapObject = {
        data: new Array(1_000_000).fill("heap memory"),
      };

      console.log("Stack values:", number, message);
      console.log("Heap object allocated.");
    }
    function releaseHeap() {
      heapObject = null; // Dereference to allow GC
      console.log("Heap object released. Wait for GC.");
    }


Stick around — I’ll keep adding practical bits here as we roll out more of the JavaScript Series >>>

Comments

Popular