These concepts separate beginner JS from production-level code. Understanding them helps with async patterns, memory, and modular apps.
1️⃣ Closures
A function that "closes over" variables from its outer scope, maintaining access even after the outer function returns. Useful for data privacy and state management.
function outer() {
let count = 0;
return function inner() {
count++;
console.log(count);
};
}
const counter = outer();
counter(); // 1
counter(); // 22️⃣ Promises & Async/Await
Promises handle async operations; async/await makes them read like sync code. Essential for APIs, timers, and non-blocking I/O.
// Promise chain
fetch(url).then(res => res.json()).then(data => console.log(data)).catch(err => console.error(err));
// Async/Await (cleaner)
async function getData() {
try {
const res = await fetch(url);
const data = await res.json();
console.log(data);
} catch (err) {
console.error(err);
}
}
3️⃣ Hoisting
Declarations (var, function) are moved to the top of their scope during compilation, but initializations stay put. let/const are block-hoisted but in a "temporal dead zone."
console.log(x); // undefined (hoisted, but not initialized)
var x = 5;
console.log(y); // ReferenceError (temporal dead zone)
let y = 10;
4️⃣ The Event Loop
JS is single-threaded; the event loop processes the call stack, then microtasks (Promises), then macrotasks (setTimeout). Explains why async code doesn't block.
5️⃣ this Keyword
Dynamic binding: refers to the object calling the method. Changes with call site, new, or explicit binding.
const obj = {
name: "Sam",
greet() {
console.log(`Hi, I'm ${this.name}`);
},
};
obj.greet(); // "Hi, I'm Sam"
// In arrow function, this is lexical
const arrowGreet = () => console.log(this.name); // undefined in global6️⃣ Spread & Rest Operators
Spread (...) expands iterables; rest collects arguments into arrays.
const nums = [1, 2, 3];
const more = [...nums, 4]; // [1, 2, 3, 4]
function sum(...args) {
return args.reduce((a, b) => a + b, 0);
}
sum(1, 2, 3); // 6
7️⃣ Destructuring
Extract values from arrays/objects into variables.
const person = { name: "John", age: 30 };
const { name, age } = person; // name = "John", age = 30
const arr = [1, 2, 3];
const [first, second] = arr; // first = 1, second = 28️⃣ Call, Apply, Bind
Explicitly set 'this' context. Call/apply invoke immediately; bind returns a new function.
function greet() {
console.log(`Hi, I'm ${this.name}`);
}
greet.call({ name: "Tom" }); // "Hi, I'm Tom"
const boundGreet = greet.bind({ name: "Alice" });
boundGreet(); // "Hi, I'm Alice"9️⃣ IIFE (Immediately Invoked Function Expression)
Self-executing function to create private scope, avoiding globals.
(function() {
console.log("Runs immediately");
let privateVar = "hidden";
})();🔟 Modules (import/export)
ES6 modules for code organization and dependency management.
// math.js
export const add = (a, b) => a + b;
export default function multiply(a, b) { return a * b; }
// main.js
import multiply, { add } from './math.js';
console.log(add(2, 3)); // 5
💡 Practice these in a Node.js REPL or browser console to see how they interact.
💬 Tap ❤️ if you're learning something new!