JavaScript Concepts
Core JavaScript concepts including closures, hoisting, prototypes, and async patterns
Questions38 shown
JavaScript is a high-level, interpreted, dynamically typed programming language.
Key characteristics:
Multi-paradigm — supports OOP, functional, and event-driven programming
Single-threaded — runs on one thread with an event loop for async operations
Dynamically typed — variables can hold any type without declaration
Prototype-based — uses prototypal inheritance instead of classical
First-class functions — functions are values that can be assigned, passed, returned
JavaScript runs in browsers (client-side) and on servers via Node.js (server-side). It is the only language that runs natively in web browsers.
JavaScript is single-threaded — it has one call stack and one memory heap.
However, it achieves concurrency through:
1. Event Loop — Continuously checks if the call stack is empty, then moves callbacks from the task queue
2. Web APIs — Browser provides setTimeout, fetch, DOM events in separate threads
3. Microtask Queue — Promises, queueMicrotask (higher priority)
4. Macrotask Queue — setTimeout, setInterval, I/O
Execution order:
1. Synchronous code (call stack)
2. Microtasks (Promise.then, queueMicrotask)
3. Macrotasks (setTimeout, setInterval)
Web Workers allow true multi-threading for CPU-intensive tasks but cannot access the DOM.
1. External script file:
<script src="app.js"></script>2. Inline script:
<script>
console.log("Hello World");
</script>Best practices:
Place scripts at the bottom of <body> or use defer/async
External files are preferred for caching and maintainability
Use type="module" for ES modules
<script src="app.js" defer></script>Primitive types (7):
1. string — "hello"
2. number — 42, 3.14, NaN, Infinity
3. boolean — true, false
4. undefined — declared but not assigned
5. null — intentional absence of value
6. symbol — unique identifiers
7. bigint — large integers 123n
Reference type:
object — includes arrays, functions, dates, regex, maps, sets
Key difference: Primitives are immutable and compared by value. Objects are mutable and compared by reference.
typeof "hello" // "string"
typeof 42 // "number"
typeof null // "object" (historic bug)
typeof undefined // "undefined"Hoisting is JavaScript's behavior of moving variable and function declarations to the top of their scope during the compilation phase.
Function declarations are fully hoisted:
sayHello(); // Works!
function sayHello() { console.log("Hi"); }`var` declarations are hoisted but initialized as undefined:
console.log(x); // undefined
var x = 5;`let`/`const` are hoisted but NOT initialized (Temporal Dead Zone):
console.log(y); // ReferenceError
let y = 5;Function expressions are NOT hoisted:
greet(); // TypeError: greet is not a function
var greet = function() { };// This works because function declarations are hoisted
sayHello(); // "Hi"
function sayHello() { console.log("Hi"); }
// This fails - TDZ
console.log(x); // ReferenceError
let x = 10;A closure is a function that retains access to its lexical scope even when executed outside that scope.
function createCounter() {
let count = 0;
return {
increment: () => ++count,
getCount: () => count,
};
}
const counter = createCounter();
counter.increment(); // 1
counter.increment(); // 2
counter.getCount(); // 2
// count is not accessible directlyUse cases:
1. Data privacy — Encapsulate variables
2. Factory functions — Create specialized functions
3. Memoization — Cache expensive computations
4. Event handlers — Preserve state in callbacks
5. Module pattern — Create private/public interfaces
function createCounter() {
let count = 0;
return {
increment: () => ++count,
getCount: () => count,
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2An IIFE (Immediately Invoked Function Expression) is a function that runs as soon as it is defined.
4 ways to create an IIFE:
// 1. Parentheses wrapper
(function() { console.log("IIFE 1"); })();
// 2. Parentheses around call
(function() { console.log("IIFE 2"); }());
// 3. Arrow function
(() => { console.log("IIFE 3"); })();
// 4. Void operator
void function() { console.log("IIFE 4"); }();Use cases:
Avoid polluting the global scope
Create private variables
Execute async code at the top level (before top-level await)
Module pattern implementation
// IIFE with parameters
const result = ((x, y) => x + y)(3, 4);
console.log(result); // 7| Feature | var | let | const |
|---------|-------|-------|--------|
| Scope | Function-scoped | Block-scoped | Block-scoped |
| Hoisting | Hoisted + initialized undefined | Hoisted + TDZ | Hoisted + TDZ |
| Re-declaration | Allowed | Not allowed | Not allowed |
| Re-assignment | Allowed | Allowed | Not allowed |
| Global object | Added to window | Not added | Not added |
if (true) {
var x = 1; // accessible outside block
let y = 2; // only in this block
const z = 3; // only in this block
}
console.log(x); // 1
console.log(y); // ReferenceErrorBest practice: Use const by default, let when reassignment is needed, avoid var.
const PI = 3.14;
let count = 0;
count = 1; // OK
// PI = 3.15; // TypeErrorA Promise is an object representing the eventual completion or failure of an asynchronous operation.
Three states:
1. Pending — Initial state, neither fulfilled nor rejected
2. Fulfilled — Operation completed successfully
3. Rejected — Operation failed
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Success!");
// or reject(new Error("Failed!"))
}, 1000);
});
promise
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(() => console.log("Done"));Promise combinators:
Promise.all() — Waits for all, fails on first rejection
Promise.allSettled() — Waits for all, returns all results
Promise.race() — Returns first settled
Promise.any() — Returns first fulfilled
const fetchData = () => new Promise((resolve, reject) => {
setTimeout(() => resolve("Data!"), 1000);
});
fetchData().then(console.log).catch(console.error);async/await is syntactic sugar over Promises that makes async code look synchronous:
// With Promises
function getUser() {
return fetch("/api/user")
.then(res => res.json())
.then(user => fetch(`/api/posts/${user.id}`))
.then(res => res.json());
}
// With async/await
async function getUser() {
const res = await fetch("/api/user");
const user = await res.json();
const postsRes = await fetch(`/api/posts/${user.id}`);
return postsRes.json();
}Error handling: Use try/catch instead of .catch()
try {
const data = await fetchData();
} catch (error) {
console.error(error);
}Key: await can only be used inside async functions (or with top-level await in modules).
async function loadData() {
try {
const response = await fetch("/api/data");
const data = await response.json();
return data;
} catch (err) {
console.error("Failed:", err);
}
}Currying transforms a function with multiple arguments into a sequence of functions each taking a single argument.
// Normal function
function add(a, b, c) { return a + b + c; }
add(1, 2, 3); // 6
// Curried version
function curriedAdd(a) {
return function(b) {
return function(c) {
return a + b + c;
};
};
}
curriedAdd(1)(2)(3); // 6Benefits:
1. Partial application — Pre-fill arguments: const add5 = curriedAdd(5);
2. Reusability — Create specialized functions from generic ones
3. Composition — Easier to compose small functions
4. Cleaner code — array.map(multiply(2)) instead of array.map(x => multiply(2, x))
const curry = (fn) => {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) return fn(...args);
return (...nextArgs) => curried(...args, ...nextArgs);
};
};
const add = curry((a, b, c) => a + b + c);
console.log(add(1)(2)(3)); // 6
console.log(add(1, 2)(3)); // 6An Execution Context is the environment where JavaScript code is evaluated and executed.
Types:
1. Global Execution Context — Created when the script starts. Sets up window (browser) or global (Node.js) and this.
2. Function Execution Context — Created each time a function is called.
3. Eval Execution Context — Created by eval() (avoid using).
Two phases:
1. Creation Phase:
- Creates variable object (hoisting)
- Sets up scope chain
- Determines this value
2. Execution Phase:
- Assigns values to variables
- Executes code line by line
The Call Stack manages execution contexts — new contexts are pushed when functions are called and popped when they return.
this refers to the object that is executing the current function. Its value depends on how the function is called:
1. Global context: this = window (browser) or global (Node.js)
2. Object method: this = the object
3. Constructor (new): this = new object being created
4. Arrow function: this = lexical this (from enclosing scope)
5. Event handler: this = element that triggered the event
6. call/apply/bind: this = explicitly set object
const obj = {
name: "Alice",
greet() { console.log(this.name); }, // "Alice"
greetArrow: () => { console.log(this.name); } // undefined
};Rule of thumb: Regular functions get this from the call site. Arrow functions get this from where they are defined.
const person = {
name: "Alice",
greet() { console.log(`Hi, ${this.name}`); }
};
person.greet(); // "Hi, Alice"
const greet = person.greet;
greet(); // "Hi, undefined" (this is window)These methods explicitly set the this value for a function:
`call(thisArg, arg1, arg2, ...)` — Calls immediately with individual args:
function greet(greeting) { console.log(`${greeting}, ${this.name}`); }
greet.call({ name: "Alice" }, "Hello"); // "Hello, Alice"`apply(thisArg, [argsArray])` — Calls immediately with array of args:
greet.apply({ name: "Bob" }, ["Hi"]); // "Hi, Bob"`bind(thisArg, arg1, ...)` — Returns a new function with bound this:
const boundGreet = greet.bind({ name: "Carol" });
boundGreet("Hey"); // "Hey, Carol"Key difference: call and apply invoke immediately; bind returns a new function.
const person = { name: "Alice" };
function greet(greeting, punct) {
return `${greeting}, ${this.name}${punct}`;
}
greet.call(person, "Hello", "!"); // "Hello, Alice!"
greet.apply(person, ["Hi", "."]); // "Hi, Alice."
const bound = greet.bind(person, "Hey");
bound("?"); // "Hey, Alice?"Every JavaScript object has an internal `[[Prototype]]` link to another object, forming a **prototype chain**. [code block] **How property lookup works:** 1. Look on the object itself 2. Look on `ob...
Create a free account to unlock login-level content, or go premium for everything.
Interview Preparation
PremiumHigh-signal questions that come up most in real interviews. These are the ones worth spending extra time on.
A **Set** is a collection of unique values — no duplicates allowed. [code block] **Differences from Arrays:** | Feature | Set | Array | |---------|-----|-------| | Duplicates | Not allowed | Allowed...
Create a free account to unlock login-level content, or go premium for everything.
A **stale closure** occurs when a closure captures a variable but the variable has changed since the closure was created. [code block] **Problem:** `var` is function-scoped, so all closures share th...
Create a free account to unlock login-level content, or go premium for everything.
A **stale closure** occurs when a closure captures a variable that has since changed, but the closure still references the old value. [code block] **Common in React:** [code block] **Fix:** Use ref...
Create a free account to unlock login-level content, or go premium for everything.
The `==` operator performs **type coercion** before comparing: [code block] **Coercion rules (simplified):** 1. `null == undefined` → true 2. Number vs String → convert String to Number 3. Boolean v...
Create a free account to unlock login-level content, or go premium for everything.
**Map** — Key-value pairs where keys can be any type: [code block] **WeakMap** — Keys must be objects and are weakly referenced: [code block] **Differences:** | Feature | Map | WeakMap | |---------|...
Create a free account to unlock login-level content, or go premium for everything.
A `Symbol` is a **unique, immutable** primitive value used as an identifier for object properties. [code block] **Use cases:** 1. **Private-like properties:** [code block] 2. **Well-known symbols:*...
Create a free account to unlock login-level content, or go premium for everything.
**`for...in`** iterates over **enumerable property names** (keys): [code block] **`for...of`** iterates over **iterable values**: [code block] | Feature | `for...in` | `for...of` | |---------|------...
Create a free account to unlock login-level content, or go premium for everything.
Functional programming (FP) is a paradigm that treats computation as the evaluation of mathematical functions. **Core principles:** 1. **Pure functions** -- Same input always produces same output, no...
Create a free account to unlock login-level content, or go premium for everything.
Inversion of Control (IoC) is a design principle where the **control flow is inverted** -- instead of your code calling library code, the framework calls your code. **With callbacks (IoC problem):** ...
Create a free account to unlock login-level content, or go premium for everything.
A tagged template literal lets you parse template literals with a custom function: [code block] **Real-world uses:** - `styled-components` -- CSS-in-JS: `` styled.div`color: red;` `` - `graphql-tag`...
Create a free account to unlock login-level content, or go premium for everything.
**Map** -- Key-value pairs where **keys can be any type**: [code block] **WeakMap** -- Keys must be **objects**, and they are **weakly held** (garbage-collectable): [code block] | Feature | Map | We...
Create a free account to unlock login-level content, or go premium for everything.
`WeakRef` creates a **weak reference** to an object, allowing it to be garbage collected even while the reference exists. [code block] **Use cases:** 1. **Caching** -- Cache objects without preventi...
Create a free account to unlock login-level content, or go premium for everything.
**`setTimeout`** -- Executes a callback after a minimum delay: [code block] **`requestAnimationFrame`** -- Executes before the next repaint, synced with display refresh rate: [code block] | Feature ...
Create a free account to unlock login-level content, or go premium for everything.