RSRobince Studio

JavaScript interview revision notes

Interview-focused revision. Written for developers preparing for an interview who want to refresh their JavaScript fast. Free, no sign-up.

49 topics in these notes

  1. What is JavaScript?
  2. JavaScript Variables (var, let, const)
  3. JavaScript Data Types
  4. Functions (declaration, expression, arrow)
  5. Truthy & Falsy in JavaScript
  6. Hoisting
  7. Scope & Closure
  8. this keyword
  9. call, apply, bind
  10. Arrays (key methods)
  11. Objects & destructuring
  12. Spread, rest, template literals
  13. == vs === (Equality)
  14. Promises & async/await
  15. Error handling (try/catch)
  16. Prototypes & inheritance
  17. Event loop
  18. Strict mode
  19. ES6 features (10 key)
  20. Callback
  21. Callback hell
  22. Null and Undefined
  23. Array (basics)
  24. Array operations
  25. Objects (basics)
  26. Class
  27. Map, Set, WeakMap, WeakSet
  28. Stack & Queue
  29. Regular Expressions (RegExp)
  30. JSON
  31. String methods
  32. Number, NaN, Infinity
  33. Optional chaining & nullish coalescing
  34. Iterators & Generators
  35. IIFE
  36. Loops (for, for...in, for...of, while)
  37. Recursion
  38. Shallow & deep copy
  39. Debounce & Throttle
  40. Error types & custom errors
  41. Date
  42. Symbol
  43. BigInt
  44. Rest parameters & arguments
  45. Getters & setters
  46. Currying
  47. Object static methods
  48. Property descriptors
  49. ES Modules (import / export)

What is JavaScript?

Simple real-life example (Understand first — very important for understanding)

  • Think of a web page that is just text and images—nothing moves or reacts.
  • Now think of a page where buttons show popups, forms validate, and content updates without reload.

That "alive" behavior on the web is powered by JavaScript. Real-world idea: one language to make pages interactive and to run on servers.

Technical definition

  • JavaScript is a high-level, interpreted, multi-paradigm language (procedural, OOP, functional).
  • Runs in the browser (front-end) and on the server (via Node.js).
  • Standardized as ECMAScript (ES5, ES6/ES2015, etc.).
  • "Java" and "JavaScript" are different languages; only the name is similar.

Simple practical example

  • Show a greeting when user clicks a button.
  • Ask for name and update text on the page without refreshing.

Code example

// Frontend: show a greeting when user clicks a button
const button = document.getElementById("greetBtn");
const message = document.getElementById("greetMsg");

button.addEventListener("click", () => {
  const name = prompt("What is your name?");
  const safeName = name && name.trim() ? name.trim() : "Guest";
  message.textContent = "Hello, " + safeName + " 👋";
});

Why it matters

  • Almost every web application uses JavaScript somewhere.
  • Understanding where it runs (browser vs Node.js) helps you decide what should happen on client vs server.

Interview tip

  • "JavaScript is the language that makes web pages interactive, runs in both browser and Node.js, and powers modern frameworks like React and Express."

JavaScript Variables (var, let, const)

Simple real-life example (Understand first — very important for understanding)

  • Think of labeled jars on a shelf: "Sugar", "Salt", "Flour".
  • The label (name) tells you what is inside (value). Some jars you never change; others you refill.

Variables are named containers for values. Real-world idea: use the right kind of jar—fixed or refillable—so your code stays clear and safe.

Technical definition

  • var: function-scoped, can be re-declared, hoisted; avoid in modern JS.
  • let: block-scoped, can be reassigned but not re-declared in same scope.
  • const: block-scoped, cannot be reassigned (but object/array contents can change).
  • Use const by default; use let only when you need reassignment.

Simple practical example

  • Use const for configuration values that never change.
  • Use let for loop counters or values that need to be updated.

Code example

var oldVar = 1;          // function-scoped, avoid
let counter = 0;          // can reassign
const API_URL = "https://api.example.com"; // cannot reassign

for (let i = 0; i < 3; i++) {
  counter += i;
}

// API_URL = "..."; // TypeError in strict mode

Why it matters

  • Choosing between var/let/const affects bugs related to scope and reassignment.
  • Modern JS codebases and interviewers expect you to prefer let/const over var.

Interview tip

  • When asked difference between var, let and const: talk about scope, hoisting, and reassignment; say you mostly use const, then let, and almost never var.

JavaScript Data Types

Simple real-life example (Understand first — very important for understanding)

  • A phone number on paper = one simple value you can copy.
  • A contact in your phone (name, numbers, notes) = a bundle of related data.

Some values are simple and copied as-is; others are bundles that you refer to from different places. Real-world idea: know which is which so you avoid surprises when copying or comparing.

Technical definition

  • Primitive types: string, number, boolean, null, undefined, symbol, bigint.
  • Reference types: object, array, function, Date, etc.
  • Primitives are stored by value; objects/arrays are stored by reference.
  • typeof null is "object" (legacy JS bug).
  • Use Array.isArray() for arrays; typeof for primitives and functions.

Simple practical example

  • Copying a number makes a new, independent value.
  • Copying an object variable makes a new reference to the same underlying object.

Code example

let age = 25;
let user = { name: "Alex", city: "Delhi" };
let ageCopy = age; ageCopy++;
let userCopy = user; userCopy.city = "Mumbai";
console.log(age, ageCopy);
console.log(user.city);

Why it matters

  • Many bugs come from not understanding value vs reference.
  • Mutating shared objects can affect code in unexpected places.

Interview tip

  • Be ready to list primitive types and explain value vs reference with a tiny example.

Functions (declaration, expression, arrow)

Simple real-life example (Understand first — very important for understanding)

  • Like a recipe: you follow the steps once, and you can reuse the same recipe anytime.
  • You can give it ingredients (inputs) and get a result (return value).

Functions are reusable steps that take inputs and can return a result. Real-world idea: name them clearly and use them so you don't repeat the same steps everywhere.

Technical definition

  • Function declaration: function add(a, b) { ... } (hoisted).
  • Function expression: const add = function(a, b) { ... } (not hoisted).
  • Arrow function: const add = (a, b) => a + b; (no own this or arguments; lexical this).
  • Use arrow functions for callbacks and small utilities.

Simple practical example

  • Reusable discount calculation for many prices.
  • Use arrow function for a small utility passed into map.

Code example

const applyDiscount = (amount, percent) => amount - (amount * percent) / 100;
const cart = [100, 250, 50];
const finalAmounts = cart.map(price => applyDiscount(price, 10));
console.log(finalAmounts);

Why it matters

  • Functions are the main building block of JS.
  • Clean, small functions with clear inputs/outputs are easier to test and reuse.

Interview tip

  • Explain declaration vs expression vs arrow; mention hoisting and this behavior for arrow functions.

Truthy & Falsy in JavaScript

Simple real-life example (Understand first — very important for understanding)

  • A switch treats "power on" and "power off" differently.
  • In conditions, some values count as "on" (true) and some as "off" (false)—even if they're not literally true or false.

Real-world idea: the language treats certain values as true or false in conditions. Knowing which ones are "off" helps you validate input and avoid bugs.

Technical definition

  • Falsy: false, 0, -0, 0n, "", null, undefined, NaN.
  • Everything else is truthy.
  • Use === instead of == to avoid unwanted coercion.

Simple practical example

  • Empty string should be treated as invalid input.
  • null/undefined should also be rejected.

Code example

function isValidInput(value) {
  return value !== null && value !== undefined && value.trim() !== "";
}
if (!isValidInput("")) console.log("Please enter a username");

Why it matters

  • Many bugs are due to unexpected truthy/falsy values.
  • Knowing the falsy list helps you write safer input checks.

Interview tip

  • List all falsy values and show a tiny example with an if check or input validation.

Hoisting

Simple real-life example (Understand first — very important for understanding)

  • Like a teacher reading the class list before everyone has arrived—they know the names in advance.
  • The language "sees" some names before it runs the code line by line.

Real-world idea: declarations are processed first in a scope. That's why you can sometimes use a name before the line where it's written—and why the rules differ for different kinds of declarations.

Technical definition

  • var and function declarations are hoisted; let/const are in a temporal dead zone until their line.
  • Only declarations are hoisted, not assignments.
  • Function expressions are not hoisted like declarations.

Code example

console.log(a);  // undefined
var a = 10;
// console.log(b);  // ReferenceError
let b = 20;
greet();  // "Hi"
function greet() { console.log("Hi"); }

Why it matters

  • Using variables before declaration gives undefined or ReferenceError depending on var vs let/const.

Interview tip

  • Hoisting is JS moving declarations to the top of scope; var is hoisted and initialized with undefined; let/const are in temporal dead zone.

Scope & Closure

Simple real-life example (Understand first — very important for understanding)

  • Like rooms in a building: what you say in one room doesn't automatically apply in another.
  • A function can "remember" things from the place it was created, even when used elsewhere.

Real-world idea: where a variable lives (scope) and what a function can still see (closure) control what your code can access. That keeps parts of the program from stepping on each other.

Technical definition

  • Scope: where a variable is visible (global, function, block).
  • Closure: a function that remembers variables from its outer scope even after that outer function has returned.
  • Use closures for data privacy, factory functions, callbacks.

Code example

function createCounter() {
  let count = 0;
  return function() { count++; return count; };
}
const counter = createCounter();
console.log(counter(), counter(), counter());  // 1, 2, 3

Why it matters

  • Closures are everywhere in JS (event handlers, callbacks, React hooks).

Interview tip

  • Closure = function + lexical environment. Give counter or private variable example and one use case.

this keyword

Simple real-life example (Understand first — very important for understanding)

  • "This" in a sentence depends on who is speaking: "I built this house" means the speaker's house.
  • In code, "this" refers to the object or context the function is running for.

Real-world idea: "this" points to the current context—often the object that "owns" the function. It changes depending on how the function is called.

Technical definition

  • In a method: this = that object.
  • In a regular function: this = global or undefined in strict mode.
  • In an arrow function: this is lexically bound (from outer scope).
  • call, apply, bind set this explicitly.

Code example

const user = { name: "Alex", greet: function() { console.log("Hello, " + this.name); } };
user.greet();  // Hello, Alex
const greetFn = user.greet;
greetFn();     // undefined (this lost)
user.greet.bind(user)();  // Hello, Alex

Why it matters

  • Many bugs come from this being different than expected in callbacks or event handlers.

Interview tip

  • this depends on how the function is called — method, standalone, arrow (outer this), and bind/call/apply.

call, apply, bind

Simple real-life example (Understand first — very important for understanding)

  • Like lending your recipe to a friend: they can use it in their kitchen (different "this") or you can say "use my kitchen" (fix "this").
  • call, apply, and bind let you choose what "this" is and how you pass the ingredients.

Real-world idea: these are ways to call a function with a specific context and arguments. Use them when you need to pass a method around or fix what "this" means.

Technical definition

  • fn.call(thisArg, arg1, arg2) — invoke immediately with thisArg and individual args.
  • fn.apply(thisArg, [arg1, arg2]) — same as call but args as an array.
  • fn.bind(thisArg) — returns a new function with this fixed; does not call immediately.

Code example

function introduce(greeting, punctuation) { console.log(greeting + ", I'm " + this.name + punctuation); }
const person = { name: "Sam" };
introduce.call(person, "Hi", "!");
introduce.apply(person, ["Hello", "."]);
const bound = introduce.bind(person);
bound("Hey", "!!");

Why it matters

  • When you pass a method as a callback, it loses its original this; bind is the classic fix.

Interview tip

  • call and apply invoke with a given this and args (call: list, apply: array). bind returns a new function with this fixed.

Arrays (key methods)

Simple real-life example (Understand first — very important for understanding)

  • Like a numbered row of boxes: first, second, third… You can add, remove, or reorder.
  • You often loop over them or use methods that find, filter, or transform items.

Real-world idea: arrays hold ordered lists. Knowing the main methods (map, filter, find, reduce) lets you work with data without writing loops every time.

Technical definition

  • map(fn) — returns new array; each element is fn(element).
  • filter(fn) — returns new array with elements where fn is truthy.
  • reduce(fn, initial) — returns single value; fn(acc, item).
  • find/findIndex, some/every, forEach for side effects.

Code example

const prices = [100, 200, 50, 300];
const withTax = prices.map(p => p * 1.18);
const expensive = prices.filter(p => p >= 100);
const total = prices.reduce((sum, p) => sum + p, 0);

Why it matters

  • Most list operations in modern JS use these methods; map/filter return new arrays (good for immutability).

Interview tip

  • Be ready to implement filter then map or a sum with reduce; mention that map/filter don't mutate the original array.

Objects & destructuring

Simple real-life example (Understand first — very important for understanding)

  • Like a form with labeled fields: name, email, age. Each label has one value.
  • You can read, add, or change values by name instead of by position.

Real-world idea: objects group related data under named keys. Destructuring is a shortcut to pull out the fields you need.

Technical definition

  • Destructuring: const { a, b } = obj; or const [x, y] = arr; to unpack values.
  • Default values: const { name = "Guest" } = obj; Rest: const { a, ...rest } = obj.
  • Shorthand: { name, age } when key and variable name match.

Code example

const user = { id: 1, name: "Alex", role: "admin" };
const { name, role } = user;
const [first, second] = [10, 20, 30];
const { name: userName, country = "India" } = user;

Why it matters

  • Destructuring makes code shorter and clearer; used everywhere in modern JS and React (props, state).

Interview tip

  • Explain object and array destructuring; mention default values and renaming (name: userName) with one-line examples.

Spread, rest, template literals

Simple real-life example (Understand first — very important for understanding)

  • Spread is like copying a list of items so you can add or merge without changing the original.
  • Rest is like saying "and everything else goes here" when you collect the remaining items.

Real-world idea: spread and rest make it easy to copy, merge, and collect values. Template literals let you write strings with variables and line breaks in a clearer way.

Technical definition

  • Spread (...): expand iterable — [...arr] (copy), { ...obj } (copy/merge).
  • Rest (... in params): collect remaining arguments — function(a, b, ...rest) {}.
  • Template literals: backticks, ${expression} for interpolation, multi-line strings.

Why it matters

Spread and rest simplify copying and merging without mutating. Template literals avoid messy string concatenation.

Code example

const a = [1, 2, 3]; const b = [...a, 4];
const opts = { ...defaults, theme: "dark" };
function sum(...nums) { return nums.reduce((s, n) => s + n, 0); }
console.log(`Hello, ${name}! Score: ${10 + 5}`);

Interview tip

Spread expands; rest collects. Give one example of spread (copy array or merge object) and one of rest (variable arguments). Mention template literals.

== vs === (Equality)

Simple real-life example (Understand first — very important for understanding)

  • Strict comparison: "same type and same value"—like matching a key to a lock.
  • Loose comparison can convert types first, which can surprise you.

Real-world idea: use strict equality (===) so you don't get hidden type conversions. Know the difference when reading or debugging code.

Technical definition

  • == (loose): compares after type coercion (e.g. 5 == "5" is true).
  • === (strict): no coercion; same value and type (5 === "5" is false).
  • Use === by default. Object.is(a, b) — like === but Object.is(NaN, NaN) is true.

Why it matters

Bugs from == often involve 0, "", null, undefined. Linters usually require ===. Common interview question.

Code example

console.log(5 == "5", 5 === "5");
console.log(null == undefined);  // true
console.log(NaN === NaN);        // false
console.log(Object.is(NaN, NaN)); // true

Interview tip

== coerces types; === does not. Prefer ===. Mention gotcha like 0 == '' or null == undefined, and Object.is for NaN.

Promises & async/await

Simple real-life example (Understand first — very important for understanding)

  • Like ordering food: you get a promise of food later; you don't stand there until it's ready.
  • You say what to do when it arrives (then) or when something goes wrong (catch).

Real-world idea: async work (network, timers) is handled with promises. async/await lets you write the "when it's done" steps in a straight line instead of nested callbacks.

Technical definition

  • Promise: value that may be available now, later, or never. States: pending, fulfilled, rejected.
  • new Promise((resolve, reject) => {}); .then / .catch / .finally.
  • async function returns a Promise; await pauses until promise settles. Use try/catch for errors.

Why it matters

Most I/O in JS is asynchronous. Promises and async/await avoid callback hell and make error handling clear.

Code example

const p = new Promise((resolve) => setTimeout(() => resolve("Done!"), 100));
p.then(msg => console.log(msg));
async function fetchUser(id) {
  try {
    const res = await fetch("/api/users/" + id);
    return await res.json();
  } catch (err) { throw err; }
}

Interview tip

Explain Promise states and that async/await is syntactic sugar over promises. Mention try/catch with await and that async functions always return a Promise.

Error handling (try/catch)

Simple real-life example (Understand first — very important for understanding)

  • When something goes wrong, you don't want the whole app to crash—you want to catch it and respond.
  • Like a safety net: try the risky step, catch the problem, and optionally clean up (finally).

Real-world idea: try/catch lets you handle errors in one place. Use it for sync code; for async, use try/catch with await or .catch() on promises.

Technical definition

  • try { } catch (err) { } finally { } — catch synchronous errors.
  • throw new Error("message"); Promise rejections are not caught by try/catch unless you await inside try or use .catch().
  • finally runs whether or not an error was thrown.

Why it matters

Without try/catch, a thrown error can crash the script. In async code, combine try/catch with await so rejections are caught.

Code example

function parseJSON(str) {
  try { return JSON.parse(str); }
  catch (e) { console.error("Invalid JSON:", e.message); return null; }
  finally { console.log("parse attempt done"); }
}

Interview tip

try/catch is for synchronous errors; for async use try/catch with await or .catch(). Say what finally is for.

Prototypes & inheritance

Simple real-life example (Understand first — very important for understanding)

  • Like a family trait: children inherit features from their parent without copying everything.
  • When you ask an object for a property, it can look on itself first, then on its "parent" chain.

Real-world idea: objects can share behavior through a prototype chain. Classes in JS are a clear way to set up this sharing.

Technical definition

  • Every object has [[Prototype]] (Object.getPrototypeOf()). When a property is not found, JS looks up the prototype chain.
  • Functions have a prototype property used when called with new; class/extends is syntactic sugar.

Why it matters

Understanding prototypes explains how inheritance and method sharing work in JS.

Code example

function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { console.log(this.name + " makes a sound"); };
const dog = new Animal("Rex");
dog.speak();
console.log(Object.getPrototypeOf(dog) === Animal.prototype);

Interview tip

Objects inherit from their prototype. When we use 'new', the new object's prototype is the constructor's prototype property. Class syntax is built on this.

Event loop

Simple real-life example (Understand first — very important for understanding)

  • Like a single clerk handling tasks: they finish one thing, then take the next from the queue.
  • Some tasks are "do this right after the current one" (microtasks); others are "do this when you get a chance" (macrotasks).

Real-world idea: JS runs one thing at a time. The event loop decides what runs next. Microtasks (e.g. promises) run before the next big task (e.g. setTimeout).

Technical definition

  • JS is single-threaded. Event loop takes tasks from call stack and task queue (and microtask queue).
  • Microtasks (Promises, queueMicrotask) run after current script and before next macrotask (e.g. setTimeout).
  • Order: sync code → microtasks → next macrotask → microtasks.

Why it matters

"What is the output?" questions often rely on event loop order. Microtasks run before the next macrotask.

Code example

console.log("1");
setTimeout(() => console.log("2"), 0);
Promise.resolve().then(() => console.log("3"));
console.log("4");
// Output: 1, 4, 3, 2

Interview tip

JS is single-threaded with an event loop; mention call stack, task queue, and microtasks. Give order-of-execution example (setTimeout vs Promise).

Strict mode

Simple real-life example (Understand first — very important for understanding)

  • Like turning on stricter rules so small mistakes become visible instead of silent.
  • Some old, loose behaviors are turned off so you write safer code.

Real-world idea: strict mode helps avoid bugs by making certain mistakes throw errors. Modern code and modules use it by default.

Technical definition

  • Enable with "use strict"; at top of file or function.
  • Disallows: undeclared variables, deleting variables, duplicate parameters; this in non-method calls becomes undefined.
  • Modules and many bundlers use strict mode by default.

Why it matters

Strict mode prevents accidental globals and other unsafe patterns.

Code example

"use strict";
let x = 10;
function showThis() { console.log(this); }  // undefined in strict
showThis();

Interview tip

Strict mode: 'use strict'. Disallows undeclared variables and makes this undefined in plain function calls. Modules are strict by default.

ES6 features (10 key)

Simple real-life example (Understand first — very important for understanding)

  • Newer JS added clearer ways to write variables, functions, and data structures.
  • let/const, arrow functions, classes, and template strings are part of everyday code now.

Real-world idea: ES6+ features make code shorter and easier to read. Interviewers often ask you to use or explain them.

Technical definition

  • let & const — block-scoped.
  • Arrow functions — () => {}; lexical this.
  • Template literals — `${expr}`.
  • Destructuring — const { a, b } = obj; const [x, y] = arr.
  • Spread & rest — ....
  • Default parameters — function f(a = 1) {}.
  • Classes — class X extends Y { }.
  • Modules — import/export.
  • Promises.
  • for...of.

Why it matters

ES6 is the baseline for modern JS; interviews ask "name some ES6 features" or "difference between let and var."

Code example

const name = "Alex";
const greet = (n) => `Hello, ${n}!`;
const [first, ...rest] = [1, 2, 3];
function sum(a = 0, b = 0) { return a + b; }

Interview tip

List 5–10: let/const, arrow functions, template literals, destructuring, spread/rest, classes, modules, Promises, default params, for...of.

Callback

Simple real-life example (Understand first — very important for understanding)

  • Like leaving your number: "Call me when it's ready." You don't wait; you get called back.
  • A callback is a function you pass so someone else can run it later.

Real-world idea: callbacks are the classic way to handle "when this is done." They're still used in many APIs and older code.

Technical definition

  • Callback: function passed as argument to be run later (e.g. when async work finishes).
  • Common in: addEventListener, setTimeout, fs.readFile, map/filter.
  • Node convention: (err, result). Nesting many callbacks = callback hell.

Why it matters

Understanding callbacks is the foundation for async JS; Promises and async/await avoid deep nesting.

Code example

setTimeout(() => console.log("Done!"), 1000);
[1, 2, 3].map((x) => x * 2);

Interview tip

Callback is a function passed to be called later. Used in events, timers, I/O. Node uses (err, result). Promises/async-await replace nested callbacks.

Callback hell

Simple real-life example (Understand first — very important for understanding)

  • When "call me when A is done" leads to "then call me when B is done" and so on—nested deeper and deeper.
  • The code becomes hard to read and to fix.

Real-world idea: nested callbacks are hard to follow. Promises and async/await are the modern way to keep async steps readable.

Technical definition

  • Callback hell: many nested callbacks, hard to read and maintain.
  • Solutions: Promises (then/catch or async/await), named functions, or async libraries.
  • async/await makes sequential async code look like synchronous code.

Why it matters

Interviewers ask "what is callback hell and how do you avoid it?" — answer: Promises and async/await.

Code example

// Prefer async/await:
const user = await getUser(id);
const orders = await getOrders(user.id);
const items = await getItems(orders[0].id);

Interview tip

Callback hell is deep nesting of callbacks. Fix with Promises and async/await, or by extracting named functions.

Null and Undefined

Simple real-life example (Understand first — very important for understanding)

  • "Nothing here" can mean "not set yet" (undefined) or "intentionally empty" (null).
  • Both mean "no value," but people use them for slightly different situations.

Real-world idea: use undefined for "not assigned"; use null when you want to say "this is intentionally empty." Checking for both avoids surprises.

Technical definition

  • undefined: variable declared but not assigned; missing property; function with no return.
  • null: intentional "no value" — often set by programmer or APIs.
  • Both falsy; null == undefined is true; === does not. value == null catches both.

Why it matters

Many bugs from not distinguishing "never set" (undefined) vs "explicitly empty" (null).

Code example

let a; console.log(a);  // undefined
const user = { name: "Alex", address: null };
console.log(null == undefined);   // true
console.log(null === undefined);  // false

Interview tip

undefined = not assigned or missing; null = intentional empty. Use == null to check both. Prefer === for strict checks.

Array (basics)

Simple real-life example (Understand first — very important for understanding)

  • An ordered list: first item, second item, and so on. You add, remove, and look up by position.
  • Indexes start at zero—like the first shelf in a row.

Real-world idea: arrays are the main way to store and work with lists. Get comfortable with length, index, and basic methods.

Technical definition

  • Ordered, zero-indexed; arr.length; create: [], Array.from().
  • Access arr[i]; out-of-range gives undefined. push, pop, shift, unshift, splice.
  • Reference types — use spread or slice() for shallow copy.

Why it matters

Arrays are used everywhere; basics plus map/filter/reduce are standard interview topics.

Code example

const arr = [10, 20, 30];
arr.push(40); arr.pop();
const copy = [...arr];
Array.from("hello");

Interview tip

Arrays: zero-indexed, .length, push/pop/shift/unshift. Reference type — copy with spread or slice.

Array operations

Simple real-life example (Understand first — very important for understanding)

  • Transform each item (map), keep only some (filter), or combine them into one value (reduce).
  • These methods replace many manual loops and keep intent clear.

Real-world idea: map, filter, and reduce are the bread-and-butter tools for list data. Use them instead of writing loops when they fit.

Technical definition

  • push/pop (end), unshift/shift (start), splice(i, deleteCount, ...items).
  • indexOf, lastIndexOf, includes, find, findIndex; sort(fn), reverse(); slice, concat, [...arr].

Why it matters

Choosing the right operation affects performance and readability.

Code example

const arr = [3, 1, 4, 1, 5];
arr.splice(2, 1, 99);
arr.indexOf(1); arr.includes(5);
arr.sort((a,b) => a - b);
const copy = arr.slice();

Interview tip

Know push/pop (stack), shift/unshift (queue), splice, indexOf/includes/find, sort/reverse. slice and spread for copy.

Objects (basics)

Simple real-life example (Understand first — very important for understanding)

  • A collection of named values: name, age, email. You read and write by key.
  • You can loop over keys, values, or entries when you need to.

Real-world idea: objects store key-value pairs. Know how to create, read, update, and iterate over them.

Technical definition

  • Key-value pairs; obj.key or obj["key"]; bracket for dynamic keys.
  • Object.keys(obj), Object.values(obj), Object.entries(obj); for (const k in obj).
  • obj.x = 1; delete obj.x; "key" in obj; obj.hasOwnProperty("key").

Why it matters

Objects are the main data structure for structured data.

Code example

const user = { name: "Alex", age: 25 };
Object.keys(user); Object.entries(user);
for (const key in user) { if (user.hasOwnProperty(key)) console.log(key, user[key]); }

Interview tip

Objects: key-value, dot or bracket access. Object.keys/values/entries for iteration.

Class

Simple real-life example (Understand first — very important for understanding)

  • Like a blueprint: you define the shape (properties and methods) once.
  • Then you create many instances that follow that blueprint.

Real-world idea: classes are a clear way to define object types and inheritance. They sit on top of the prototype system.

Technical definition

  • ES6 class is syntactic sugar over prototypes; constructor runs when new ClassName() is called.
  • extends for inheritance; super() must be called in subclass constructor before using this.
  • static methodName() {}; get prop() {}; set prop(v) {}; #privateField (ES2022).

Why it matters

Classes are the standard way to do OOP in modern JS; interviews ask about extends, super, and prototypes.

Code example

class Person { constructor(name) { this.name = name; } greet() { return "Hello, " + this.name; } }
class Student extends Person { constructor(name, grade) { super(name); this.grade = grade; } }
const s = new Student("Alex", 10); s.greet();

Interview tip

class is syntax over prototypes. constructor, extends, super(). Call super() before this in subclass. Static methods live on the class.

Map, Set, WeakMap, WeakSet

Simple real-life example (Understand first — very important for understanding)

  • Map: like an object that uses any value as key and keeps insertion order.
  • Set: like a list that never stores the same value twice—good for unique items.

Real-world idea: use Map when you need keys that aren't strings or need order; use Set when you need a unique collection.

Technical definition

  • Map: key-value; keys any type; set, get, has, delete, size; iteration via forEach or for...of.
  • Set: unique values; add, has, delete, size; use for deduplication.
  • WeakMap/WeakSet: keys objects only; entries can be GC'd when key has no other reference; no iteration, no size.

Code example

const map = new Map();
map.set("name", "Alex"); map.set(1, "one");
const set = new Set([1, 2, 2, 3]); set.add(4);
[...set];  // dedupe

Interview tip

Map: any key type, .size, insertion order. Set: unique values. WeakMap/WeakSet: keys objects, no iteration, GC-friendly.

Stack & Queue

Simple real-life example (Understand first — very important for understanding)

  • Stack: last in, first out—like a stack of plates. You add and remove from the top.
  • Queue: first in, first out—like a line. You add at the back, take from the front.

Real-world idea: stack and queue are two simple patterns for ordering data. They show up in algorithms and in real code.

Technical definition

  • Stack: LIFO — push(item), pop(). Use array: push/pop.
  • Queue: FIFO — enqueue (push), dequeue (shift). shift is O(n).

Code example

const stack = []; stack.push(1); stack.push(2); stack.pop();
const queue = []; queue.push("a"); queue.push("b"); queue.shift();

Interview tip

Stack: LIFO, push/pop. Queue: FIFO, push + shift. Mention shift is O(n) if asked about performance.

Regular Expressions (RegExp)

Simple real-life example (Understand first — very important for understanding)

  • Like a search pattern: "starts with a digit," "has an @ in the middle," "three letters then a number."
  • You use it to find, validate, or replace text that matches the pattern.

Real-world idea: regular expressions describe text patterns. Use them for validation and search; keep them simple or document them.

Technical definition

  • Create: /pattern/flags or new RegExp('pattern', 'gi'). Flags: g, i, m.
  • .test(str), .exec(str); str.match(regex), str.replace(regex, repl), str.split(regex).
  • \d digit, \w word, \s space; + * ?; [a-z]; ^ $; capture groups ().

Code example

"a1b22c".match(/\d+/g);
"hello".replace(/l/g, "L");
/^[a-z]+@[a-z]+\.[a-z]+$/i.test("a@b.co");

Interview tip

Know test, exec, match, replace; flags g and i; character classes and quantifiers; capture groups for replace ($1, $2).

JSON

Simple real-life example (Understand first — very important for understanding)

  • Like a standard format for writing down data so different systems can read it.
  • You turn objects into a string to send or store, then parse the string back when you need it.

Real-world idea: JSON is the common format for APIs and config. You stringify to send and parse to read.

Technical definition

  • JSON.stringify(obj), JSON.parse(str). Replacer/reviver for custom serialization.
  • Only serializes: objects, arrays, strings, numbers, booleans, null. Not: functions, undefined, Symbol, Date (becomes string), circular refs (throws).

Code example

JSON.stringify({ a: 1, b: "x" });
JSON.parse('{"a":1}');

Interview tip

stringify/parse; replacer/reviver; circular refs and undefined/Date limitations.

String methods

Simple real-life example (Understand first — very important for understanding)

  • Strings have built-in helpers: split into parts, trim spaces, change case, find a substring.
  • You use them to clean and check user input or to build messages.

Real-world idea: string methods let you work with text without writing everything from scratch. Know the main ones for interviews and daily use.

Technical definition

  • indexOf, lastIndexOf, includes, startsWith, endsWith; slice, substring; split(sep); trim, toLowerCase, toUpperCase, repeat, padStart, padEnd; replace (first only unless regex g), replaceAll.

Code example

"  hi  ".trim();
"abc".includes("b"); "abc".padStart(5, "0");
"a-b-c".split("-");

Interview tip

Know includes, startsWith, endsWith, slice, split, trim, replace; strings are immutable.

Number, NaN, Infinity

Simple real-life example (Understand first — very important for understanding)

  • When a math operation has no sensible number result (e.g. 0/0), you get a special "not a number" value.
  • It's the only value that isn't equal to itself—so you check with isNaN() or Number.isNaN().

Real-world idea: NaN means the result of a number operation wasn't a real number. Check for it when doing math or parsing numbers.

Technical definition

  • parseInt(str, radix), parseFloat(str). Number.isNaN(x) (prefer over isNaN — isNaN coerces), Number.isFinite(x), Number.isInteger(x).
  • NaN !== NaN; use Number.isNaN. Math.floor, ceil, round, max, min, random, abs.

Code example

parseInt("10", 10); parseInt("10px");
Number.isNaN(NaN); isNaN("hello");
Math.floor(2.7);

Interview tip

NaN !== NaN; use Number.isNaN. parseInt second arg for radix. isNaN vs Number.isNaN — coercion.

Optional chaining & nullish coalescing

Simple real-life example (Understand first — very important for understanding)

  • Like asking "if there is a door, open it" instead of "open the door" when the door might not exist.
  • You use ?. so the code stops safely when something in the chain is null or undefined.

Real-world idea: optional chaining (?.) lets you read nested properties without writing long if-checks. If any part is missing, you get undefined instead of an error.

Technical definition

  • obj?.prop, obj?.[key], fn?.() — short-circuits to undefined if obj is null/undefined.
  • a ?? b — nullish coalescing: use b only when a is null or undefined. Unlike ||, 0 and "" are kept. a ??= b for assign when null/undefined.

Code example

o?.a?.b;
null ?? 5;   // 5
0 ?? 5;     // 0

Interview tip

?. for safe property/method access; ?? for defaults when null/undefined only; difference from || (0 and '').

Iterators & Generators

Simple real-life example (Understand first — very important for understanding)

  • An iterator is like a bookmark: you can ask for the "next" item until there are no more.
  • A generator is a function that yields values one at a time, so you can loop over them or pull on demand.

Real-world idea: iterators and generators let you work with sequences lazily—one step at a time—which can save memory and keep code clear.

Technical definition

  • Iterator: object with next() returning { value, done }. Iterable: has Symbol.iterator. for...of uses iterables.
  • Generator: function* gen() { yield 1; }; returns iterator; lazy evaluation.

Code example

function* ids() { yield 1; yield 2; }
const it = ids();
it.next(); it.next(); it.next();

Interview tip

Iterator: next() → { value, done }. Iterable: Symbol.iterator. Generator: function*, yield; lazy and composable.

IIFE

Simple real-life example (Understand first — very important for understanding)

  • Like running a small recipe once as soon as you open the book—you don't save it for later.
  • A function that is defined and called immediately, often to create a private scope.

Real-world idea: IIFE runs code once and can hide variables from the rest of the script. Older code used it a lot; modules and block scope often replace it now.

Technical definition

  • Immediately Invoked Function Expression: (function() { })(); runs once, creates private scope.
  • Used historically to avoid polluting global and to capture loop variables (before let/const).

Code example

(function() {
  const secret = 10;
  console.log(secret);
})();

Interview tip

IIFE: define and run in one go; creates scope; used for privacy and old-style modules.

Loops (for, for...in, for...of, while)

Simple real-life example (Understand first — very important for understanding)

  • for: "do this a fixed number of times" or "go through each index."
  • for...of: "go through each value in a list." for...in: "go through each key in an object."

Real-world idea: pick the loop that matches what you're doing—by index, by value, or by key—so the code is clear and you avoid off-by-one errors.

Technical definition

  • for (i=0; i<n; i++), while (cond), do { } while (cond).
  • for...in — enumerable property keys (object); use Object.hasOwn to skip inherited; avoid for arrays.
  • for...of — iterable values (array, string, Map, Set). break, continue, label for nested loops.

Code example

for (const x of [1, 2, 3]) console.log(x);
const o = { a: 1, b: 2 };
for (const k in o) console.log(k, o[k]);

Interview tip

for...in = keys (object); for...of = values (iterable). Don't use for...in for arrays if you care about order.

Recursion

Simple real-life example (Understand first — very important for understanding)

  • Like a task that breaks into smaller versions of the same task: "solve for n by solving for n-1 and combining."
  • You need a base case (when to stop) and a recursive case (call itself with a smaller input).

Real-world idea: recursion is when a function calls itself. Use it when the structure of the problem is self-similar (trees, divide-and-conquer).

Technical definition

  • Function calls itself; needs base case and recursive case. Tail recursion: last action is recursive call.
  • Use for tree/graph traversal, divide-and-conquer, factorial, flatten. Watch stack overflow for deep recursion.

Code example

function factorial(n) {
  if (n <= 1) return 1;
  return n * factorial(n - 1);
}
factorial(5);  // 120

Interview tip

Always have a base case; explain stack; mention tail recursion and stack overflow for very deep recursion.

Shallow & deep copy

Simple real-life example (Understand first — very important for understanding)

  • Shallow copy: copy the top level; anything nested is still shared (like copying a folder but not the files inside).
  • Deep copy: copy everything at every level so nothing is shared.

Real-world idea: copying objects isn't always "full copy." Know when you need a shallow vs deep copy so changes don't surprise you.

Technical definition

  • Shallow: [...arr], { ...obj }, Object.assign({}, obj). Nested objects still shared.
  • Deep: JSON.parse(JSON.stringify(obj)) — loses functions, Date, undefined, circular. structuredClone(obj) handles many types and circular; not functions.

Code example

const a = [{ x: 1 }]; const b = [...a]; b[0].x = 2; a[0].x;  // 2
const c = structuredClone(a); c[0].x = 3; a[0].x;  // still 2

Interview tip

Shallow: spread, slice, assign — nested shared. Deep: structuredClone or JSON round-trip; know limitations.

Debounce & Throttle

Simple real-life example (Understand first — very important for understanding)

  • Debounce: "run this only after they've stopped doing it for a moment" (e.g. search after typing stops).
  • Throttle: "run this at most every X time" (e.g. scroll handler once per 100 ms).

Real-world idea: both limit how often something runs. Debounce waits for quiet; throttle spreads calls out over time. Use them for resize, scroll, or input.

Technical definition

  • Debounce: run only after no calls for X ms; resets on each call. Use: search on type, resize.
  • Throttle: run at most once every X ms. Use: scroll, mousemove, rate-limited API. Implement with setTimeout + clearTimeout (debounce); timestamp or flag (throttle).

Code example

function debounce(fn, ms) {
  let t;
  return function(...args) { clearTimeout(t); t = setTimeout(() => fn.apply(this, args), ms); };
}
function throttle(fn, ms) {
  let last = 0;
  return function(...args) { const now = Date.now(); if (now - last >= ms) { last = now; fn.apply(this, args); } };
}

Interview tip

Debounce: wait for silence then run (search). Throttle: run at most every N ms (scroll). Know how to implement both.

Error types & custom errors

Simple real-life example (Understand first — very important for understanding)

  • Errors have types (SyntaxError, TypeError, ReferenceError) so you know what went wrong.
  • You can throw your own errors with a message and catch them to handle specific cases.

Real-world idea: use the right error type and message so debugging is easier. Catch, log or handle, and optionally rethrow.

Technical definition

  • Built-in: Error, TypeError, ReferenceError, SyntaxError, RangeError. throw new Error('msg').
  • Custom: class MyError extends Error { constructor(m) { super(m); this.name = 'MyError'; } }. Use instanceof in catch. finally runs always.

Code example

throw new TypeError("Expected number");
try { JSON.parse("invalid"); } catch (e) { console.log(e instanceof SyntaxError); }

Interview tip

Know Error, TypeError, ReferenceError, SyntaxError; custom errors extend Error; try/catch/finally; finally runs always.

Date

Simple real-life example (Understand first — very important for understanding)

  • Dates are a single "moment in time" stored inside the computer.
  • You create, format, and compare them—but watch out for time zones and daylight saving.

Real-world idea: Date is the built-in way to work with time. For serious date logic or time zones, libraries like date-fns or Luxon help.

Technical definition

  • new Date(), new Date(ms), new Date(year, month, day...) — month 0-indexed.
  • getFullYear, getMonth, getDate, getHours, getTime; toISOString(), toLocaleString(); Date.parse(str).

Code example

const d = new Date();
d.getTime(); d.toISOString();
new Date(0);  // 1970-01-01 UTC

Interview tip

Month 0–11; getTime() for timestamp; toISOString for JSON/APIs; timezone gotchas (UTC vs local).

Symbol

Simple real-life example (Understand first — very important for understanding)

  • Like a unique label that can't clash with any other label—even if the name is the same.
  • Useful for object properties that should stay hidden or unique.

Real-world idea: symbols give you unique keys. They're used for well-known protocols (e.g. iteration) and for hiding implementation details.

Technical definition

  • Symbol() — unique value every time. Symbol('desc') for debugging. Use as object keys for uniqueness.
  • Symbol.for('key') — global registry. Well-known: Symbol.iterator, Symbol.toStringTag, Symbol.toPrimitive.

Code example

const s = Symbol("id");
const o = { [s]: 1, name: "x" };
o[s];  // 1
Object.keys(o);  // ["name"]

Interview tip

Symbol = unique id; good for object keys to avoid collision; Symbol.iterator for custom iteration.

BigInt

Simple real-life example (Understand first — very important for understanding)

  • When normal numbers are too big (e.g. beyond 2^53), you need a different type.
  • BigInt lets you do integer math on arbitrarily large whole numbers.

Real-world idea: use BigInt when you need integers larger than the safe range. You can't mix them with normal numbers without converting.

Technical definition

  • BigInt(123) or 123n. Cannot mix with Number in same expression without converting. Use when beyond Number.MAX_SAFE_INTEGER (2^53 - 1). JSON.stringify drops BigInt unless custom replacer.

Code example

const n = 9007199254740993n;
n + 1n;
Number(n);  // precision loss

Interview tip

BigInt for integers > 2^53-1; 123n or BigInt(); can't mix with Number; JSON needs custom replacer.

Rest parameters & arguments

Simple real-life example (Understand first — very important for understanding)

  • "Give me the first item, and put everything else in a bag."
  • Rest (...rest) collects the remaining arguments or array elements into one array.

Real-world idea: rest parameters let functions accept "and any number more" arguments. Spread is the opposite—unpacking an array into separate items.

Technical definition

  • Rest: function f(...args) — args is a real array of all extra arguments. Prefer over arguments.
  • arguments: array-like, exists in non-arrow functions. Rest must be last parameter.

Code example

function sum(...nums) { return nums.reduce((a, b) => a + b, 0); }
sum(1, 2, 3);  // 6

Interview tip

...rest is real array; arguments is array-like and only in non-arrow; prefer rest.

Getters & setters

Simple real-life example (Understand first — very important for understanding)

  • Like a receptionist: you don't touch the filing cabinet directly; you ask for a value or request a change.
  • Getters and setters run code when someone reads or writes a property.

Real-world idea: getters/setters hide how a value is stored and let you validate or compute on read/write. They make properties behave like methods.

Technical definition

  • get prop() { return this._x; }, set prop(v) { this._x = v; }. Access like normal property. Same in class body. Object.defineProperty(obj, 'prop', { get, set }).

Code example

const o = { _n: 0, get n() { return this._n; }, set n(v) { if (typeof v === 'number') this._n = v; } };
o.n = 10; o.n;

Interview tip

get/set look like properties but run code; use for validation or computed values.

Currying

Simple real-life example (Understand first — very important for understanding)

  • Like a function that takes one ingredient at a time: first the base, then the flavor, then you get the result.
  • Each call returns a new function that waits for the next argument.

Real-world idea: currying turns a multi-argument function into a chain of one-argument steps. It's useful for reuse and composition.

Technical definition

  • Currying: function that takes one (or more) arg and returns function taking the next, until all args collected. f(a)(b)(c).
  • Partial application: fix some args, return function for the rest. Use for configuration, composition.

Code example

const add = a => b => a + b;
add(1)(2);  // 3
const add1 = add(1); add1(5);  // 6

Interview tip

Currying: f(a)(b) instead of f(a,b); returns function until all args supplied; useful for partial application.

Object static methods

Simple real-life example (Understand first — very important for understanding)

  • Some methods belong to the "blueprint" itself, not to each instance—like a factory rule that applies to all products.
  • Object.keys(), Object.assign(), and Object.freeze() are examples.

Real-world idea: static methods live on the constructor or Object itself. They're tools for working with objects and types.

Technical definition

  • Object.keys(obj), Object.values(obj), Object.entries(obj), Object.fromEntries(entries).
  • Object.assign(target, ...sources) — mutates target. Object.freeze(obj), Object.seal(obj). Object.create(proto), Object.hasOwn(obj, key).

Code example

Object.entries({ a: 1, b: 2 });
Object.fromEntries([["a", 1]]);
Object.freeze({ x: 1 });

Interview tip

keys, values, entries, fromEntries; assign for merge/shallow copy; freeze/seal for immutability; create for prototype; hasOwn for own props.

Property descriptors

Simple real-life example (Understand first — very important for understanding)

  • Each property has hidden settings: can it be written? listed? changed or deleted?
  • You can define or read them to make properties read-only, non-enumerable, etc.

Real-world idea: descriptors control how a property behaves. Use them when you need fine control over what code can do with an object.

Technical definition

  • Each property has: value, writable, enumerable, configurable. Accessor: get, set (no value/writable).
  • Object.getOwnPropertyDescriptor(obj, 'key'), Object.defineProperty(obj, 'key', descriptor). enumerable controls keys() and for...in.

Code example

const o = {};
Object.defineProperty(o, 'x', { value: 1, writable: false, enumerable: true });
o.x = 2;  // no effect in strict; o.x stays 1

Interview tip

Descriptor: value, writable, enumerable, configurable; get/set for accessors; defineProperty/getOwnPropertyDescriptor.

ES Modules (import / export)

Simple real-life example (Understand first — very important for understanding)

  • Like a standard way to say "use this from that file" and "this file exports these things."
  • import and export are the keywords; the system loads modules and avoids naming clashes.

Real-world idea: ES modules are the modern way to split and share code. They run in strict mode and have a clear dependency graph.

Technical definition

  • Export: export const x = 1; export function f() {}; export default class C {}. One default per file.
  • Import: import x from './m.js' (default); import { a, b } from './m.js' (named); import * as M from './m.js' (namespace).
  • Modules are strict, own scope, async load. Browser: script type="module"; Node: type: module or .mjs.

Code example

// utils.js
export const add = (a, b) => a + b;
export default function greet() { return 'Hi'; }
// app.js
import greet, { add } from './utils.js';

Interview tip

export/export default; import default, import { named }; ES modules have own scope, strict, async load. type=module in browser; type:module or .mjs in Node.

More Frontend notes

HTML · CSS · JavaScript in the Browser · TypeScript · React · Angular · All developer notes