DEV Community

Nadim Chowdhury
Nadim Chowdhury

Posted on

🧠 MODULE 1: JavaScript Core (Very Deep Dive)

If you're serious about becoming a strong JavaScript developer (especially as a full-stack dev), this module is your foundation. These are not just interview topics β€” they shape how JavaScript thinks.

Let’s break them down clearly, deeply, and in a practical human way.


βœ… 1.1 Language Fundamentals


πŸ”Ή 1. var, let, const

These are used to declare variables β€” but they behave very differently.

var

  • Function scoped
  • Can be redeclared
  • Hoisted (initialized as undefined)
  • Causes bugs in modern code
var x = 10;
var x = 20; // Allowed
Enter fullscreen mode Exit fullscreen mode

⚠️ Avoid in modern JS unless you understand legacy behavior.


let

  • Block scoped
  • Cannot be redeclared in same scope
  • Hoisted but in Temporal Dead Zone
let count = 5;
count = 6; // Allowed
Enter fullscreen mode Exit fullscreen mode

const

  • Block scoped
  • Cannot be reassigned
  • Must be initialized
const PI = 3.14;
Enter fullscreen mode Exit fullscreen mode

⚠️ Important:
const does NOT make objects immutable β€” it only prevents reassignment.

const user = { name: "Nadim" };
user.name = "John"; // Allowed
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 2. Scope (Block vs Function)

Scope determines where variables are accessible.

Function Scope

Created by functions.
var follows this.

function test() {
  var x = 10;
}
console.log(x); // ❌ Error
Enter fullscreen mode Exit fullscreen mode

Block Scope

Created by { }
let and const follow this.

{
  let a = 5;
}
console.log(a); // ❌ Error
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 3. Hoisting

JavaScript moves declarations to the top during compilation.

console.log(a); // undefined
var a = 10;
Enter fullscreen mode Exit fullscreen mode

Behind the scenes:

var a;
console.log(a);
a = 10;
Enter fullscreen mode Exit fullscreen mode

But with let and const:

console.log(b); // ❌ ReferenceError
let b = 20;
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 4. Temporal Dead Zone (TDZ)

The time between entering scope and variable declaration.

{
  console.log(x); // ❌ ReferenceError
  let x = 5;
}
Enter fullscreen mode Exit fullscreen mode

This protected zone prevents accidental access before initialization.


πŸ”Ή 5. Closures (Very Important)

A closure is when a function remembers variables from its outer scope even after the outer function has finished executing.

function outer() {
  let counter = 0;

  return function inner() {
    counter++;
    console.log(counter);
  }
}

const increment = outer();
increment(); // 1
increment(); // 2
Enter fullscreen mode Exit fullscreen mode

Even though outer() is done, inner() still remembers counter.

πŸ’‘ Used in:

  • Data privacy
  • Factory functions
  • React hooks

πŸ”Ή 6. Lexical Scope

Functions access variables based on where they are defined, not where they are called.

function outer() {
  let name = "Nadim";

  function inner() {
    console.log(name);
  }

  inner();
}
Enter fullscreen mode Exit fullscreen mode

Scope is determined at writing time, not runtime.


πŸ”Ή 7. Prototypes

JavaScript uses prototype-based inheritance.

Every object has a hidden [[Prototype]].

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log("Hello " + this.name);
}

const p1 = new Person("Nadim");
p1.greet();
Enter fullscreen mode Exit fullscreen mode

All instances share prototype methods (memory efficient).


πŸ”Ή 8. this Keyword (Interview Favorite)

this depends on HOW a function is called.

In object method:

const user = {
  name: "Nadim",
  greet() {
    console.log(this.name);
  }
}
Enter fullscreen mode Exit fullscreen mode

this = object


In normal function:

function test() {
  console.log(this);
}
Enter fullscreen mode Exit fullscreen mode

In browser β†’ window
In strict mode β†’ undefined


In constructor:

this = new object


πŸ”Ή 9. Arrow Functions

Arrow functions behave differently with this.

const greet = () => {
  console.log(this);
}
Enter fullscreen mode Exit fullscreen mode

Arrow functions:

  • Do NOT have their own this
  • Inherit this from surrounding scope
  • Cannot be used as constructors

Good for callbacks.

Bad for object methods (sometimes).


πŸ”Ή 10. Call, Apply, Bind

Used to control this.

function greet() {
  console.log("Hi " + this.name);
}

const user = { name: "Nadim" };

greet.call(user);
Enter fullscreen mode Exit fullscreen mode

call()

Arguments passed separately.

greet.call(user, arg1, arg2);
Enter fullscreen mode Exit fullscreen mode

apply()

Arguments passed as array.

greet.apply(user, [arg1, arg2]);
Enter fullscreen mode Exit fullscreen mode

bind()

Returns new function.

const newFunc = greet.bind(user);
newFunc();
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 11. Destructuring

Extract values from objects/arrays easily.

Object:

const user = { name: "Nadim", age: 25 };
const { name, age } = user;
Enter fullscreen mode Exit fullscreen mode

Array:

const arr = [1, 2, 3];
const [a, b] = arr;
Enter fullscreen mode Exit fullscreen mode

Cleaner and readable.


πŸ”Ή 12. Spread & Rest Operators (...)

Same symbol. Different purpose.


Spread (expands)

const arr1 = [1,2];
const arr2 = [...arr1, 3,4];
Enter fullscreen mode Exit fullscreen mode

Used for:

  • Copying arrays
  • Merging objects

Rest (collects)

function sum(...numbers) {
  return numbers.reduce((a,b) => a+b);
}
Enter fullscreen mode Exit fullscreen mode

Collects remaining arguments into array.


🎯 Final Thoughts

If you deeply understand:

  • Scope
  • Closures
  • this
  • Prototypes
  • Hoisting

You’re already above 70% of JavaScript developers.

Most developers memorize syntax.
Strong developers understand behavior.

And interviews?
They test behavior.


βœ… 1.2 Asynchronous JavaScript (Deep Dive – Interview Ready)

JavaScript is single-threaded.
That means it can do one thing at a time.

But then how does it handle:

  • API calls 🌐
  • Timers ⏳
  • File reading πŸ“‚
  • Database queries πŸ’Ύ

That’s where Asynchronous JavaScript comes in.

Let’s break this down clearly and deeply.


πŸ” 1. Event Loop (The Heart of Async JS)

The Event Loop is the mechanism that allows JavaScript to handle async operations without blocking the main thread.

Think of it like a manager:

  1. Checks if Call Stack is empty
  2. If empty β†’ pushes tasks from the queue
  3. Keeps everything running smoothly

Without the event loop, JS would freeze every time it waits for data.


πŸ“š 2. Call Stack

The Call Stack is where JavaScript executes functions.

It works like a stack (LIFO – Last In First Out).

function one() {
  two();
}

function two() {
  console.log("Hello");
}

one();
Enter fullscreen mode Exit fullscreen mode

Execution order:

  • one() pushed
  • two() pushed
  • console.log() pushed
  • Then everything pops out

If the stack is busy β†’ nothing else runs.

That’s why synchronous heavy code blocks the UI.


βš–οΈ 3. Microtask vs Macrotask (Very Important for Interviews)

JavaScript has two main queues:

🟑 Macrotask Queue

Examples:

  • setTimeout
  • setInterval
  • setImmediate
  • DOM events
setTimeout(() => {
  console.log("Timeout");
}, 0);
Enter fullscreen mode Exit fullscreen mode

πŸ”΅ Microtask Queue

Higher priority than macrotasks.

Examples:

  • Promise.then
  • catch
  • finally
  • queueMicrotask
Promise.resolve().then(() => {
  console.log("Promise");
});
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ Execution Priority

Order:

  1. Call Stack
  2. Microtask Queue
  3. Macrotask Queue

Example:

console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

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

console.log("End");
Enter fullscreen mode Exit fullscreen mode

Output:

Start
End
Promise
Timeout
Enter fullscreen mode Exit fullscreen mode

Even though timeout is 0ms, promises run first.

Why?
Because microtasks are processed before macrotasks.

This is a common interview trap question.


🀝 4. Promises

A Promise represents a value that may be available now, later, or never.

States:

  • Pending
  • Fulfilled
  • Rejected
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Data received");
  }, 1000);
});
Enter fullscreen mode Exit fullscreen mode

Consume it:

promise
  .then(data => console.log(data))
  .catch(err => console.log(err));
Enter fullscreen mode Exit fullscreen mode

Promise Chaining

fetchData()
  .then(data => process(data))
  .then(result => console.log(result))
  .catch(err => console.log(err));
Enter fullscreen mode Exit fullscreen mode

Each .then() returns a new promise.


πŸš€ 5. Async / Await

Cleaner syntax for promises.

async function getData() {
  const response = await fetch(url);
  const data = await response.json();
  console.log(data);
}
Enter fullscreen mode Exit fullscreen mode

Important:

  • async makes function return a promise
  • await pauses execution inside async function
  • It does NOT block the main thread

It only pauses that function.


❌ 6. Error Handling in Async Code

With Promises

fetchData()
  .then(res => console.log(res))
  .catch(err => console.log("Error:", err));
Enter fullscreen mode Exit fullscreen mode

With Async/Await (Recommended)

async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.log("Error:", error);
  }
}
Enter fullscreen mode Exit fullscreen mode

Always use try/catch with async-await.


⚠️ Important Interview Question:

What if you forget await?

const data = fetchData();
console.log(data);
Enter fullscreen mode Exit fullscreen mode

You’ll get a Promise, not actual data.


⚑ 7. Promise Utility Methods

These are powerful.


πŸ”Ή Promise.all()

Runs multiple promises in parallel.

If ONE fails β†’ entire thing fails.

Promise.all([promise1, promise2])
  .then(results => console.log(results))
  .catch(err => console.log(err));
Enter fullscreen mode Exit fullscreen mode

Best when:

  • All results required
  • Fast parallel execution needed

πŸ”Ή Promise.race()

Returns first settled promise (resolve OR reject).

Promise.race([p1, p2])
  .then(result => console.log(result));
Enter fullscreen mode Exit fullscreen mode

Used for:

  • Timeouts
  • First response wins

πŸ”Ή Promise.allSettled()

Waits for ALL promises.
Does NOT fail if one rejects.

Promise.allSettled([p1, p2])
  .then(results => console.log(results));
Enter fullscreen mode Exit fullscreen mode

Returns:

[
  { status: "fulfilled", value: ... },
  { status: "rejected", reason: ... }
]
Enter fullscreen mode Exit fullscreen mode

Best when:

  • You want all results regardless of failure

🧠 Deep Concept Understanding

When async code runs:

  1. Async operation goes to Web APIs (browser/Node)
  2. After completion β†’ callback goes to Queue
  3. Event loop checks stack
  4. Moves task to Call Stack

JavaScript is single-threaded.
Concurrency is managed by the event loop system.


🎯 Final Thoughts

If you deeply understand:

  • Event Loop
  • Microtask vs Macrotask
  • Promise chaining
  • Async/Await behavior
  • Error handling patterns

You are already thinking like a senior developer.

Most devs use async.
Few understand how it actually works internally.


βœ… 1.2 Asynchronous JavaScript (Deep Dive – Interview Ready)

JavaScript is single-threaded.
That means it can do one thing at a time.

But then how does it handle:

  • API calls 🌐
  • Timers ⏳
  • File reading πŸ“‚
  • Database queries πŸ’Ύ

That’s where Asynchronous JavaScript comes in.

Let’s break this down clearly and deeply.


πŸ” 1. Event Loop (The Heart of Async JS)

The Event Loop is the mechanism that allows JavaScript to handle async operations without blocking the main thread.

Think of it like a manager:

  1. Checks if Call Stack is empty
  2. If empty β†’ pushes tasks from the queue
  3. Keeps everything running smoothly

Without the event loop, JS would freeze every time it waits for data.


πŸ“š 2. Call Stack

The Call Stack is where JavaScript executes functions.

It works like a stack (LIFO – Last In First Out).

function one() {
  two();
}

function two() {
  console.log("Hello");
}

one();
Enter fullscreen mode Exit fullscreen mode

Execution order:

  • one() pushed
  • two() pushed
  • console.log() pushed
  • Then everything pops out

If the stack is busy β†’ nothing else runs.

That’s why synchronous heavy code blocks the UI.


βš–οΈ 3. Microtask vs Macrotask (Very Important for Interviews)

JavaScript has two main queues:

🟑 Macrotask Queue

Examples:

  • setTimeout
  • setInterval
  • setImmediate
  • DOM events
setTimeout(() => {
  console.log("Timeout");
}, 0);
Enter fullscreen mode Exit fullscreen mode

πŸ”΅ Microtask Queue

Higher priority than macrotasks.

Examples:

  • Promise.then
  • catch
  • finally
  • queueMicrotask
Promise.resolve().then(() => {
  console.log("Promise");
});
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ Execution Priority

Order:

  1. Call Stack
  2. Microtask Queue
  3. Macrotask Queue

Example:

console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

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

console.log("End");
Enter fullscreen mode Exit fullscreen mode

Output:

Start
End
Promise
Timeout
Enter fullscreen mode Exit fullscreen mode

Even though timeout is 0ms, promises run first.

Why?
Because microtasks are processed before macrotasks.

This is a common interview trap question.


🀝 4. Promises

A Promise represents a value that may be available now, later, or never.

States:

  • Pending
  • Fulfilled
  • Rejected
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("Data received");
  }, 1000);
});
Enter fullscreen mode Exit fullscreen mode

Consume it:

promise
  .then(data => console.log(data))
  .catch(err => console.log(err));
Enter fullscreen mode Exit fullscreen mode

Promise Chaining

fetchData()
  .then(data => process(data))
  .then(result => console.log(result))
  .catch(err => console.log(err));
Enter fullscreen mode Exit fullscreen mode

Each .then() returns a new promise.


πŸš€ 5. Async / Await

Cleaner syntax for promises.

async function getData() {
  const response = await fetch(url);
  const data = await response.json();
  console.log(data);
}
Enter fullscreen mode Exit fullscreen mode

Important:

  • async makes function return a promise
  • await pauses execution inside async function
  • It does NOT block the main thread

It only pauses that function.


❌ 6. Error Handling in Async Code

With Promises

fetchData()
  .then(res => console.log(res))
  .catch(err => console.log("Error:", err));
Enter fullscreen mode Exit fullscreen mode

With Async/Await (Recommended)

async function getData() {
  try {
    const data = await fetchData();
    console.log(data);
  } catch (error) {
    console.log("Error:", error);
  }
}
Enter fullscreen mode Exit fullscreen mode

Always use try/catch with async-await.


⚠️ Important Interview Question:

What if you forget await?

const data = fetchData();
console.log(data);
Enter fullscreen mode Exit fullscreen mode

You’ll get a Promise, not actual data.


⚑ 7. Promise Utility Methods

These are powerful.


πŸ”Ή Promise.all()

Runs multiple promises in parallel.

If ONE fails β†’ entire thing fails.

Promise.all([promise1, promise2])
  .then(results => console.log(results))
  .catch(err => console.log(err));
Enter fullscreen mode Exit fullscreen mode

Best when:

  • All results required
  • Fast parallel execution needed

πŸ”Ή Promise.race()

Returns first settled promise (resolve OR reject).

Promise.race([p1, p2])
  .then(result => console.log(result));
Enter fullscreen mode Exit fullscreen mode

Used for:

  • Timeouts
  • First response wins

πŸ”Ή Promise.allSettled()

Waits for ALL promises.
Does NOT fail if one rejects.

Promise.allSettled([p1, p2])
  .then(results => console.log(results));
Enter fullscreen mode Exit fullscreen mode

Returns:

[
  { status: "fulfilled", value: ... },
  { status: "rejected", reason: ... }
]
Enter fullscreen mode Exit fullscreen mode

Best when:

  • You want all results regardless of failure

🧠 Deep Concept Understanding

When async code runs:

  1. Async operation goes to Web APIs (browser/Node)
  2. After completion β†’ callback goes to Queue
  3. Event loop checks stack
  4. Moves task to Call Stack

JavaScript is single-threaded.
Concurrency is managed by the event loop system.


🎯 Final Thoughts

If you deeply understand:

  • Event Loop
  • Microtask vs Macrotask
  • Promise chaining
  • Async/Await behavior
  • Error handling patterns

You are already thinking like a senior developer.

Most devs use async.
Few understand how it actually works internally.


βœ… 1.3 Advanced JavaScript Concepts (Deep + Interview Ready)

Now we’re entering the zone where developers become strong engineers.

These topics are heavily asked in:

  • Frontend interviews
  • React interviews
  • Performance optimization rounds
  • Senior-level discussions

Let’s break them down clearly, practically, and deeply.


πŸ”Ή 1. Debounce

Debounce ensures a function runs only after a certain delay, and only if no new event occurs during that delay.

πŸ’‘ Think: β€œWait until user stops typing.”

Real-world use:

  • Search input API calls
  • Resize events
  • Auto-save features

Example:

function debounce(fn, delay) {
  let timer;

  return function (...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const search = debounce(() => {
  console.log("API Call");
}, 500);
Enter fullscreen mode Exit fullscreen mode

If user types quickly β†’ API runs only once after typing stops.


πŸ”Ή 2. Throttle

Throttle ensures a function runs at most once in a given time interval.

πŸ’‘ Think: β€œLimit how often it runs.”

Real-world use:

  • Scroll events
  • Button spam prevention
  • Game input controls

Example:

function throttle(fn, limit) {
  let inThrottle;

  return function (...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

πŸ”₯ Debounce vs Throttle (Interview Question)

Debounce Throttle
Waits for pause Runs at fixed interval
Best for search Best for scroll
Executes after delay Executes immediately (usually)

πŸ”Ή 3. Currying

Currying transforms a function with multiple arguments into multiple functions each taking one argument.

Instead of:

function add(a, b) {
  return a + b;
}
Enter fullscreen mode Exit fullscreen mode

We write:

function curryAdd(a) {
  return function (b) {
    return a + b;
  };
}

curryAdd(2)(3); // 5
Enter fullscreen mode Exit fullscreen mode

Modern Arrow Version:

const add = a => b => a + b;
Enter fullscreen mode Exit fullscreen mode

Why is Currying useful?

  • Function reusability
  • Functional programming
  • Partial application

Example:

const multiply = a => b => a * b;
const double = multiply(2);
double(5); // 10
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 4. Memoization

Memoization caches function results to avoid recalculating expensive operations.

πŸ’‘ Think: β€œIf I’ve already solved this, don’t calculate again.”

Example:

function memoize(fn) {
  const cache = {};

  return function (...args) {
    const key = JSON.stringify(args);

    if (cache[key]) {
      return cache[key];
    }

    const result = fn(...args);
    cache[key] = result;
    return result;
  };
}
Enter fullscreen mode Exit fullscreen mode

Usage:

const slowAdd = (a, b) => {
  console.log("Calculating...");
  return a + b;
};

const fastAdd = memoize(slowAdd);

fastAdd(2,3); // Calculating...
fastAdd(2,3); // Cached
Enter fullscreen mode Exit fullscreen mode

Used heavily in:

  • React performance optimization
  • Expensive computations
  • Dynamic programming

πŸ”Ή 5. Deep Clone

Deep cloning creates a completely independent copy of an object.

Simple way (not perfect):

const copy = JSON.parse(JSON.stringify(obj));
Enter fullscreen mode Exit fullscreen mode

⚠️ But this fails for:

  • Dates
  • Functions
  • Undefined
  • Circular references

Better modern way:

const copy = structuredClone(obj);
Enter fullscreen mode Exit fullscreen mode

Best approach depends on use case.


πŸ”Ή 6. Shallow vs Deep Copy

This is VERY important.


Shallow Copy

Copies only first level.

const obj = { a: 1, b: { c: 2 } };
const copy = { ...obj };

copy.b.c = 100;
console.log(obj.b.c); // 100 ❗
Enter fullscreen mode Exit fullscreen mode

Nested objects still share reference.


Deep Copy

Copies everything including nested objects.

Now modifying copy won’t affect original.


Interview Trick Question:

Spread operator creates?
πŸ‘‰ Shallow copy.


πŸ”Ή 7. Garbage Collection

JavaScript automatically manages memory.

It uses Mark-and-Sweep algorithm.

How it works:

  1. Mark all reachable objects
  2. Remove unreachable ones

You don’t manually free memory like C/C++.

But…

Just because GC exists doesn’t mean memory problems disappear.


πŸ”Ή 8. Memory Leaks

Memory leak happens when memory is allocated but never released.

Over time β†’ app slows β†’ crashes.


Common Causes

1. Unused global variables

var data = new Array(1000000);
Enter fullscreen mode Exit fullscreen mode

Global variables stay in memory.


2. Forgotten timers

setInterval(() => {
  console.log("Running...");
}, 1000);
Enter fullscreen mode Exit fullscreen mode

If not cleared β†’ keeps running.


3. Event listeners not removed

element.addEventListener("click", handler);
Enter fullscreen mode Exit fullscreen mode

If element removed but listener not cleaned β†’ memory leak.


4. Closures holding references

Closures can accidentally keep large objects in memory.


How to Prevent Memory Leaks

  • Remove event listeners
  • Clear intervals/timeouts
  • Avoid unnecessary globals
  • Use weak references when needed (WeakMap, WeakSet)

🧠 Final Understanding

If you truly understand:

  • Debounce & Throttle β†’ performance control
  • Currying β†’ functional mastery
  • Memoization β†’ optimization
  • Deep vs Shallow copy β†’ reference control
  • Garbage collection β†’ memory lifecycle
  • Memory leaks β†’ production stability

You’re no longer a beginner.

You’re thinking like someone who understands how JavaScript behaves internally.


βœ… 1.4 Coding Practice Topics (Interview Implementation Guide)

Now we move from theory β†’ implementation.

In interviews, they don’t just ask:

β€œWhat is map?”

They ask:

β€œCan you implement map without using the built-in method?”

This section will prepare you for real coding rounds.


πŸ”Ή 1. Custom map()

Native map() transforms each element and returns a new array.

Custom Implementation:

Array.prototype.myMap = function (callback) {
  const result = [];

  for (let i = 0; i < this.length; i++) {
    result.push(callback(this[i], i, this));
  }

  return result;
};
Enter fullscreen mode Exit fullscreen mode

Usage:

const arr = [1, 2, 3];

const doubled = arr.myMap(num => num * 2);
console.log(doubled); // [2, 4, 6]
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 2. Custom filter()

Returns elements that satisfy condition.

Array.prototype.myFilter = function (callback) {
  const result = [];

  for (let i = 0; i < this.length; i++) {
    if (callback(this[i], i, this)) {
      result.push(this[i]);
    }
  }

  return result;
};
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 3. Custom reduce()

Reduces array to single value.

Array.prototype.myReduce = function (callback, initialValue) {
  let accumulator = initialValue ?? this[0];
  let startIndex = initialValue ? 0 : 1;

  for (let i = startIndex; i < this.length; i++) {
    accumulator = callback(accumulator, this[i], i, this);
  }

  return accumulator;
};
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 4. Flatten Nested Array

Input:

[1, [2, [3, 4]], 5]
Enter fullscreen mode Exit fullscreen mode

Output:

[1, 2, 3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Recursive Solution:

function flatten(arr) {
  let result = [];

  for (let item of arr) {
    if (Array.isArray(item)) {
      result = result.concat(flatten(item));
    } else {
      result.push(item);
    }
  }

  return result;
}
Enter fullscreen mode Exit fullscreen mode

Modern Shortcut:

arr.flat(Infinity);
Enter fullscreen mode Exit fullscreen mode

But interviewers prefer manual logic.


πŸ”Ή 5. Group By Function

Group items by a property.

Input:

[
  { name: "A", age: 20 },
  { name: "B", age: 20 },
  { name: "C", age: 25 }
]
Enter fullscreen mode Exit fullscreen mode

Output:

{
  20: [{...}, {...}],
  25: [{...}]
}
Enter fullscreen mode Exit fullscreen mode

Implementation:

function groupBy(arr, key) {
  return arr.reduce((acc, item) => {
    const groupKey = item[key];

    if (!acc[groupKey]) {
      acc[groupKey] = [];
    }

    acc[groupKey].push(item);

    return acc;
  }, {});
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 6. Remove Duplicates

Using Set:

const unique = arr => [...new Set(arr)];
Enter fullscreen mode Exit fullscreen mode

Manual Way:

function removeDuplicates(arr) {
  const seen = {};
  const result = [];

  for (let item of arr) {
    if (!seen[item]) {
      seen[item] = true;
      result.push(item);
    }
  }

  return result;
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 7. Deep Clone

Basic version:

function deepClone(obj) {
  if (obj === null || typeof obj !== "object") return obj;

  if (Array.isArray(obj)) {
    return obj.map(item => deepClone(item));
  }

  const cloned = {};

  for (let key in obj) {
    cloned[key] = deepClone(obj[key]);
  }

  return cloned;
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 8. LRU Cache (Very Popular Interview Question)

LRU = Least Recently Used

When capacity is full β†’ remove least recently used item.


Implementation using Map:

class LRUCache {
  constructor(limit) {
    this.limit = limit;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) return -1;

    const value = this.cache.get(key);

    this.cache.delete(key);
    this.cache.set(key, value);

    return value;
  }

  put(key, value) {
    if (this.cache.has(key)) {
      this.cache.delete(key);
    }

    this.cache.set(key, value);

    if (this.cache.size > this.limit) {
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Why Map?
Because it preserves insertion order.


πŸ”Ή 9. Debounce (Reimplementation)

function debounce(fn, delay) {
  let timer;

  return function (...args) {
    clearTimeout(timer);

    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}
Enter fullscreen mode Exit fullscreen mode

πŸ”Ή 10. Throttle (Reimplementation)

function throttle(fn, limit) {
  let inThrottle;

  return function (...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;

      setTimeout(() => {
        inThrottle = false;
      }, limit);
    }
  };
}
Enter fullscreen mode Exit fullscreen mode

🧠 How Interviewers Judge You

They check:

  • Do you handle edge cases?
  • Do you understand time complexity?
  • Can you explain your logic clearly?
  • Do you know why this works?

🎯 Pro Interview Tips

When implementing:

  1. Start with brute force
  2. Then optimize
  3. Mention time complexity
  4. Discuss edge cases

Example:

  • Flatten β†’ O(n)
  • GroupBy β†’ O(n)
  • LRU β†’ O(1) for get/put

If you master these implementations,
you are ready for:

  • FAANG-style frontend interviews
  • Senior JS rounds
  • React system design discussions

Top comments (0)