<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[i_codefullstack]]></title><description><![CDATA[i_codefullstack]]></description><link>https://blogs.arnabsamanta.in</link><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 12:58:35 GMT</lastBuildDate><atom:link href="https://blogs.arnabsamanta.in/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[From Callback Hell to Promise Land: Async JavaScript in Node.js]]></title><description><![CDATA[Asynchronous code is one of the first things that trips up developers coming to Node.js. You write what looks like a perfectly normal function call, and somehow the result isn't there when you expect ]]></description><link>https://blogs.arnabsamanta.in/from-callback-hell-to-promise-land-async-javascript-in-node-js</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/from-callback-hell-to-promise-land-async-javascript-in-node-js</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Fri, 17 Apr 2026 08:30:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/5e7a13f1-6c16-4cf4-b510-3dfac5e7bdc8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Asynchronous code is one of the first things that trips up developers coming to Node.js. You write what looks like a perfectly normal function call, and somehow the result isn't there when you expect it. You restructure things, add some nesting, and suddenly your code looks like a staircase going off the screen.</p>
<p>This article walks through why async exists in Node.js, how callbacks work under the hood, why they become a problem at scale, and how Promises solve those problems cleanly.</p>
<hr />
<h2>Why Async Code Exists in Node.js</h2>
<p>Node.js runs on a single thread. There is no thread pool doing work in parallel by default — it's one thread, running one thing at a time.</p>
<p>So how does Node.js handle thousands of concurrent requests without blocking?</p>
<p>The answer is the <strong>event loop</strong> combined with <strong>non-blocking I/O</strong>. When Node.js performs an operation that takes time — reading a file, querying a database, making an HTTP request — it hands that work off to the operating system and moves on. When the OS finishes, it puts the result in a queue. The event loop picks that up and runs your callback.</p>
<pre><code class="language-plaintext">┌────────────────────────────────────────┐
│              Your Code                 │
│                                        │
│  fs.readFile("data.txt", callback) ──► │──► OS handles file read
│                                        │         │
│  ...continues executing...             │         ▼
│                                        │   [Event Loop Queue]
│  ◄──────────────────────────────────── │◄── callback(data) fires
└────────────────────────────────────────┘
</code></pre>
<p>This is why you cannot do this:</p>
<pre><code class="language-js">let content;
fs.readFile("data.txt", "utf8", (err, data) =&gt; {
  content = data;
});

console.log(content); // undefined — the file hasn't been read yet
</code></pre>
<p>The <code>readFile</code> call is non-blocking. Execution moves past it immediately. The file content arrives later, on the event loop, when the OS is done.</p>
<p>This is the foundation everything else builds on.</p>
<hr />
<h2>Callback-Based Async Execution</h2>
<p>A <strong>callback</strong> is just a function you pass to another function, to be called when an async operation is done.</p>
<p>Here is the simplest possible example:</p>
<pre><code class="language-js">const fs = require("fs");

fs.readFile("user.txt", "utf8", function (err, data) {
  if (err) {
    console.error("Failed to read file:", err.message);
    return;
  }
  console.log("File contents:", data);
});
</code></pre>
<h3>Step-by-step: What actually happens</h3>
<pre><code class="language-plaintext">1. fs.readFile() is called
   └─ Node registers the file read with the OS
   └─ Execution continues immediately (non-blocking)

2. Event loop keeps spinning
   └─ Other code can run while file is being read

3. OS completes the file read
   └─ Result is pushed to the event loop queue

4. Event loop picks it up
   └─ Your callback is called with (err, data)

5. Inside the callback:
   └─ err is null if successful
   └─ data contains the file contents
</code></pre>
<p>The <strong>error-first callback convention</strong> (also called Node.js callback style) is the standard pattern. The first argument is always an error object (or <code>null</code> if no error), and the second is the result.</p>
<pre><code class="language-js">function doSomethingAsync(input, callback) {
  setTimeout(() =&gt; {
    if (!input) {
      return callback(new Error("Input is required"));
    }
    callback(null, `Processed: ${input}`);
  }, 100);
}

doSomethingAsync("hello", (err, result) =&gt; {
  if (err) {
    console.error(err.message);
    return;
  }
  console.log(result); // "Processed: hello"
});
</code></pre>
<p>This works fine for a single async operation. The trouble starts when you need to chain them.</p>
<hr />
<h2>Problems with Nested Callbacks</h2>
<p>Imagine this scenario: you need to read a user's config file, use the user ID from that file to fetch their profile from a database, and then log the activity.</p>
<p>Each step depends on the previous one. With callbacks, that looks like this:</p>
<pre><code class="language-js">const fs = require("fs");
const db = require("./db");
const logger = require("./logger");

fs.readFile("config.json", "utf8", (err, configData) =&gt; {
  if (err) {
    console.error("Could not read config:", err.message);
    return;
  }

  const config = JSON.parse(configData);

  db.getUser(config.userId, (err, user) =&gt; {
    if (err) {
      console.error("Could not fetch user:", err.message);
      return;
    }

    db.getUserPosts(user.id, (err, posts) =&gt; {
      if (err) {
        console.error("Could not fetch posts:", err.message);
        return;
      }

      logger.log(user.id, "fetched posts", (err) =&gt; {
        if (err) {
          console.error("Could not log activity:", err.message);
          return;
        }

        console.log(`\({user.name} has \){posts.length} posts`);
      });
    });
  });
});
</code></pre>
<p>This is <strong>callback hell</strong> — sometimes called the "pyramid of doom" because of how the indentation keeps growing to the right.</p>
<h3>The specific problems this causes</h3>
<p><strong>1. Error handling is repetitive and easy to miss</strong></p>
<p>Every single callback needs its own error check. If you forget one — or handle it inconsistently — errors silently disappear or crash the process in unexpected ways.</p>
<p><strong>2. The flow is hard to follow</strong></p>
<p>Reading this code top to bottom doesn't tell you the sequence clearly. You have to trace the nesting to understand what runs when.</p>
<p><strong>3. You can't use try/catch</strong></p>
<pre><code class="language-js">// This does NOT work for async callbacks
try {
  fs.readFile("data.txt", "utf8", (err, data) =&gt; {
    throw new Error("something went wrong");
  });
} catch (e) {
  console.error(e); // never runs
}
</code></pre>
<p>The <code>throw</code> inside the callback happens on a future tick of the event loop — the <code>try/catch</code> is long gone by then.</p>
<p><strong>4. Returning early doesn't stop anything</strong></p>
<pre><code class="language-js">fs.readFile("data.txt", "utf8", (err, data) =&gt; {
  if (err) return; // stops this callback, but async work is already in flight
  // ...
});
</code></pre>
<p><strong>5. Reusing steps is awkward</strong></p>
<p>If you want to share step 2 (fetch user) in multiple places, you end up passing deeply nested callbacks around, which only makes things worse.</p>
<hr />
<h2>Promise-Based Async Handling</h2>
<p>A <strong>Promise</strong> is an object that represents the eventual result of an async operation. It has three states:</p>
<pre><code class="language-plaintext">┌─────────────────────────────────────────────┐
│                  PROMISE                    │
│                                             │
│   PENDING ──► FULFILLED (resolved value)   │
│          └──► REJECTED  (error reason)      │
│                                             │
│  Once settled (fulfilled or rejected),      │
│  a Promise never changes state.             │
└─────────────────────────────────────────────┘
</code></pre>
<p>Here is the same file read operation using a Promise:</p>
<pre><code class="language-js">const fs = require("fs").promises;

fs.readFile("user.txt", "utf8")
  .then((data) =&gt; {
    console.log("File contents:", data);
  })
  .catch((err) =&gt; {
    console.error("Failed to read file:", err.message);
  });
</code></pre>
<h3>Chaining: the real power</h3>
<p>Let's rewrite the callback hell example using Promises. Assume each function returns a Promise:</p>
<pre><code class="language-js">const fs = require("fs").promises;

fs.readFile("config.json", "utf8")
  .then((configData) =&gt; {
    const config = JSON.parse(configData);
    return db.getUser(config.userId); // return the next Promise
  })
  .then((user) =&gt; {
    return db.getUserPosts(user.id).then((posts) =&gt; ({ user, posts }));
  })
  .then(({ user, posts }) =&gt; {
    return logger.log(user.id, "fetched posts").then(() =&gt; ({ user, posts }));
  })
  .then(({ user, posts }) =&gt; {
    console.log(`\({user.name} has \){posts.length} posts`);
  })
  .catch((err) =&gt; {
    // one handler catches errors from any step above
    console.error("Something went wrong:", err.message);
  });
</code></pre>
<p>One <code>.catch()</code> at the end handles errors from any step. The chain reads top to bottom. Each <code>.then()</code> receives the resolved value of the previous step.</p>
<h3>Creating your own Promises</h3>
<p>If you're wrapping a callback-based API, you create Promises manually:</p>
<pre><code class="language-js">function readFilePromise(path) {
  return new Promise((resolve, reject) =&gt; {
    fs.readFile(path, "utf8", (err, data) =&gt; {
      if (err) {
        reject(err); // triggers .catch()
      } else {
        resolve(data); // triggers .then()
      }
    });
  });
}

readFilePromise("config.json")
  .then((data) =&gt; console.log(data))
  .catch((err) =&gt; console.error(err.message));
</code></pre>
<h3>async/await: cleaner Promise syntax</h3>
<p><code>async/await</code> is syntax sugar over Promises. Under the hood, it's exactly the same — Promises all the way down. But it reads like synchronous code:</p>
<pre><code class="language-js">const fs = require("fs").promises;

async function loadUserData() {
  try {
    const configData = await fs.readFile("config.json", "utf8");
    const config = JSON.parse(configData);

    const user = await db.getUser(config.userId);
    const posts = await db.getUserPosts(user.id);

    await logger.log(user.id, "fetched posts");

    console.log(`\({user.name} has \){posts.length} posts`);
  } catch (err) {
    console.error("Something went wrong:", err.message);
  }
}

loadUserData();
</code></pre>
<p>Every <code>await</code> pauses execution inside the <code>async</code> function until the Promise resolves. The <code>try/catch</code> works exactly as expected.</p>
<h3>Running Promises in parallel</h3>
<p>When operations don't depend on each other, you can run them at the same time:</p>
<pre><code class="language-js">async function loadDashboard(userId) {
  // These three requests fire simultaneously
  const [profile, posts, notifications] = await Promise.all([
    db.getUser(userId),
    db.getUserPosts(userId),
    db.getNotifications(userId),
  ]);

  return { profile, posts, notifications };
}
</code></pre>
<p>With callbacks, parallelism like this requires tracking completion manually with counters or external state. With <code>Promise.all</code>, it's one line.</p>
<hr />
<h2>Benefits of Promises</h2>
<p>Here is a direct comparison of the same scenario:</p>
<p><strong>Callback version:</strong></p>
<pre><code class="language-js">getUser(id, (err, user) =&gt; {
  if (err) return handleError(err);
  getPosts(user.id, (err, posts) =&gt; {
    if (err) return handleError(err);
    getComments(posts[0].id, (err, comments) =&gt; {
      if (err) return handleError(err);
      render(user, posts, comments);
    });
  });
});
</code></pre>
<p><strong>Promise version:</strong></p>
<pre><code class="language-js">getUser(id)
  .then((user) =&gt; getPosts(user.id))
  .then((posts) =&gt; getComments(posts[0].id))
  .then((comments) =&gt; render(user, posts, comments))
  .catch(handleError);
</code></pre>
<p><strong>async/await version:</strong></p>
<pre><code class="language-js">try {
  const user = await getUser(id);
  const posts = await getPosts(user.id);
  const comments = await getComments(posts[0].id);
  render(user, posts, comments);
} catch (err) {
  handleError(err);
}
</code></pre>
<h3>Summary of benefits</h3>
<table>
<thead>
<tr>
<th>Problem with Callbacks</th>
<th>How Promises Solve It</th>
</tr>
</thead>
<tbody><tr>
<td>Repeated error handling in every callback</td>
<td>Single <code>.catch()</code> handles all errors in a chain</td>
</tr>
<tr>
<td>Deeply nested, hard-to-read code</td>
<td>Flat <code>.then()</code> chain or <code>await</code> reads top-to-bottom</td>
</tr>
<tr>
<td>Can't use try/catch</td>
<td><code>async/await</code> restores try/catch behavior</td>
</tr>
<tr>
<td>Hard to run things in parallel</td>
<td><code>Promise.all()</code>, <code>Promise.race()</code>, <code>Promise.allSettled()</code></td>
</tr>
<tr>
<td>Error swallowing</td>
<td>Unhandled rejections surface clearly in Node.js</td>
</tr>
<tr>
<td>Difficult to compose</td>
<td>Promises are values — pass them, return them, store them</td>
</tr>
</tbody></table>
<hr />
<h2>Putting It Together</h2>
<p>Here is a complete, realistic example using the built-in <code>https</code> module, wrapped in Promises, using <code>async/await</code>:</p>
<pre><code class="language-js">const https = require("https");

function fetchJSON(url) {
  return new Promise((resolve, reject) =&gt; {
    https.get(url, (res) =&gt; {
      let raw = "";

      res.on("data", (chunk) =&gt; (raw += chunk));
      res.on("end", () =&gt; {
        try {
          resolve(JSON.parse(raw));
        } catch (err) {
          reject(new Error("Invalid JSON response"));
        }
      });
      res.on("error", reject);
    });
  });
}

async function getPostWithAuthor(postId) {
  const post = await fetchJSON(
    `https://jsonplaceholder.typicode.com/posts/${postId}`
  );

  const author = await fetchJSON(
    `https://jsonplaceholder.typicode.com/users/${post.userId}`
  );

  return {
    title: post.title,
    body: post.body,
    author: author.name,
    email: author.email,
  };
}

getPostWithAuthor(1)
  .then((result) =&gt; console.log(result))
  .catch((err) =&gt; console.error("Error:", err.message));
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>The progression from callbacks to Promises to <code>async/await</code> isn't just syntax preference — each step solves real, tangible problems that arise when writing non-trivial async code.</p>
<ul>
<li><p><strong>Callbacks</strong> work, but they don't compose well and they make error handling fragile.</p>
</li>
<li><p><strong>Promises</strong> give you a proper value to work with, a flat chain, and a single place to handle errors.</p>
</li>
<li><p><strong>async/await</strong> makes Promise-based code look and behave like synchronous code, without actually blocking.</p>
</li>
</ul>
<p>Modern Node.js (and the browser) use Promises everywhere. <code>fs.promises</code>, <code>fetch</code>, and most third-party libraries return Promises by default. Learning to work with them fluently is not optional — it's the baseline for writing reliable Node.js code.</p>
<p>Start with the examples above, convert a callback-based function to a Promise yourself, and then rewrite it with <code>async/await</code>. The difference will be immediately apparent.</p>
]]></content:encoded></item><item><title><![CDATA[Promises in JavaScript: A Better Way to Handle Asynchronous Code]]></title><description><![CDATA[If you have worked with callbacks for any length of time, you have felt the friction. Functions nested inside functions, error handling repeated at every level, logic that reads bottom-up instead of t]]></description><link>https://blogs.arnabsamanta.in/promises-in-javascript-a-better-way-to-handle-asynchronous-code</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/promises-in-javascript-a-better-way-to-handle-asynchronous-code</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 09:28:34 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/b6ad13c0-b2da-43f8-aa01-4513b1f81155.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have worked with callbacks for any length of time, you have felt the friction. Functions nested inside functions, error handling repeated at every level, logic that reads bottom-up instead of top-down. Callbacks work, but they fight you when the async logic gets complex.</p>
<p>Promises were designed to fix that friction. They give asynchronous operations a cleaner interface — one that separates "start this operation" from "handle the result," and chains multiple async steps in a way that reads naturally.</p>
<hr />
<h2>What Problem Promises Solve</h2>
<p>Callbacks have a fundamental shape problem. When async operations depend on each other, callbacks nest:</p>
<pre><code class="language-js">getUser(id, function(err, user) {
  if (err) return handleError(err);

  getOrders(user.id, function(err, orders) {
    if (err) return handleError(err);

    getOrderDetails(orders[0].id, function(err, details) {
      if (err) return handleError(err);

      console.log("Details:", details);
    });
  });
});
</code></pre>
<p>Each step lives inside the previous one. The deeper the dependency chain, the further right the code drifts. Error handling is duplicated at every level. Variables from outer steps are trapped in their own scope and difficult to share.</p>
<p>This pattern is called <strong>callback hell</strong> or the <strong>pyramid of doom</strong> — and the shape of the code itself is the problem.</p>
<p>Promises flatten this structure:</p>
<pre><code class="language-js">getUser(id)
  .then(user =&gt; getOrders(user.id))
  .then(orders =&gt; getOrderDetails(orders[0].id))
  .then(details =&gt; console.log("Details:", details))
  .catch(err =&gt; handleError(err));
</code></pre>
<p>Same logic. Same operations. But now the steps read top to bottom, errors are handled once at the end, and each step is a clean, separate line. The structure of the code reflects the sequence of operations.</p>
<hr />
<h2>What a Promise Is</h2>
<p>A Promise is an object that represents the eventual result of an asynchronous operation. You can think of it as a placeholder — a commitment that a value will be available at some point in the future, even though it is not available right now.</p>
<p>The analogy is a restaurant receipt. When you place an order, you get a ticket. The food is not ready yet, but you hold something that <em>represents</em> the food. When it is ready, you exchange the ticket for the meal. If the kitchen runs out of ingredients, you are notified of the failure. The ticket is the Promise — it stands in for a future outcome.</p>
<pre><code class="language-js">const promise = new Promise((resolve, reject) =&gt; {
  // asynchronous work happens here
  // call resolve(value) on success
  // call reject(reason) on failure
});
</code></pre>
<p>A Promise is created with a function called the <strong>executor</strong>. The executor receives two functions: <code>resolve</code> and <code>reject</code>. Call <code>resolve</code> when the operation succeeds, passing the result. Call <code>reject</code> when it fails, passing the reason or error.</p>
<hr />
<h2>Promise States</h2>
<p>Every Promise exists in exactly one of three states:</p>
<p><strong>Pending</strong> — the initial state. The operation has started but has not yet completed. The Promise has no value yet.</p>
<p><strong>Fulfilled</strong> — the operation completed successfully. The Promise has a resolved value. This is sometimes called "resolved."</p>
<p><strong>Rejected</strong> — the operation failed. The Promise holds a rejection reason, typically an <code>Error</code> object.</p>
<pre><code class="language-plaintext">         resolve(value)
Pending ─────────────────► Fulfilled
         reject(reason)
Pending ─────────────────► Rejected
</code></pre>
<p>Once a Promise moves from pending to either fulfilled or rejected, it is <strong>settled</strong>. A settled Promise never changes state. A fulfilled Promise stays fulfilled. A rejected Promise stays rejected. The transition is one-way and permanent.</p>
<pre><code class="language-js">const willFulfill = new Promise((resolve) =&gt; {
  setTimeout(() =&gt; resolve("success!"), 1000);
});

const willReject = new Promise((_, reject) =&gt; {
  setTimeout(() =&gt; reject(new Error("something failed")), 1000);
});
</code></pre>
<p>Both start in the pending state. After 1 second, each moves to its settled state — one fulfilled, one rejected.</p>
<hr />
<h2>The Basic Promise Lifecycle</h2>
<h3>Creating a Promise</h3>
<pre><code class="language-js">function fetchUser(id) {
  return new Promise((resolve, reject) =&gt; {
    setTimeout(() =&gt; {
      if (id &gt; 0) {
        resolve({ id, name: "Priya", role: "admin" });
      } else {
        reject(new Error("Invalid user ID"));
      }
    }, 500);
  });
}
</code></pre>
<p><code>fetchUser</code> returns a Promise immediately. The executor runs the async work (simulated here with <code>setTimeout</code>). On success, <code>resolve</code> is called with the user object. On failure, <code>reject</code> is called with an error.</p>
<h3>Consuming the result</h3>
<p>You access the resolved value with <code>.then()</code> and the rejection reason with <code>.catch()</code>:</p>
<pre><code class="language-js">fetchUser(1)
  .then(user =&gt; {
    console.log("Got user:", user.name); // Got user: Priya
  })
  .catch(err =&gt; {
    console.log("Error:", err.message);
  });
</code></pre>
<p>The <code>.then()</code> callback runs if the Promise fulfills. The <code>.catch()</code> callback runs if it rejects. Neither runs synchronously — both are deferred until the Promise settles.</p>
<h3>Full lifecycle in one example</h3>
<pre><code class="language-js">console.log("1: Start");

const p = new Promise((resolve) =&gt; {
  console.log("2: Executor runs synchronously");
  setTimeout(() =&gt; {
    console.log("4: Resolving after 1 second");
    resolve("the value");
  }, 1000);
});

p.then(value =&gt; {
  console.log("5: Fulfilled with:", value);
});

console.log("3: After .then() registration");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">1: Start
2: Executor runs synchronously
3: After .then() registration
4: Resolving after 1 second
5: Fulfilled with: the value
</code></pre>
<p>The executor runs immediately when the Promise is created — line 2 appears before line 3. But the <code>.then()</code> callback is deferred — it only runs after the Promise resolves (line 5 appears last). This is the key timing: creation is synchronous, settlement callbacks are asynchronous.</p>
<hr />
<h2>Handling Success and Failure</h2>
<h3><code>.then()</code> — handling fulfillment</h3>
<p><code>.then()</code> accepts up to two arguments: a fulfillment handler and an optional rejection handler. In practice, most code uses separate <code>.then()</code> and <code>.catch()</code> calls for clarity.</p>
<pre><code class="language-js">fetchUser(1).then(
  user =&gt; console.log("Success:", user.name), // fulfillment handler
  err  =&gt; console.log("Error:", err.message)  // rejection handler (optional)
);
</code></pre>
<h3><code>.catch()</code> — handling rejection</h3>
<p><code>.catch(fn)</code> is equivalent to <code>.then(null, fn)</code>. It catches rejections from the Promise it is called on, and also from any previous <code>.then()</code> in the chain:</p>
<pre><code class="language-js">fetchUser(-1)
  .then(user =&gt; processUser(user))
  .catch(err =&gt; {
    console.log("Caught:", err.message); // Caught: Invalid user ID
  });
</code></pre>
<p>If <code>fetchUser(-1)</code> rejects, <code>.then()</code> is skipped entirely and <code>.catch()</code> receives the rejection reason.</p>
<h3><code>.finally()</code> — always runs</h3>
<p><code>.finally()</code> runs regardless of whether the Promise fulfilled or rejected. It receives no arguments and is used for cleanup:</p>
<pre><code class="language-js">showSpinner();

fetchUser(1)
  .then(user =&gt; renderUser(user))
  .catch(err =&gt; showError(err.message))
  .finally(() =&gt; hideSpinner()); // always runs
</code></pre>
<p><code>hideSpinner</code> runs whether the fetch succeeded or failed. Without <code>.finally()</code>, you would need to call it in both <code>.then()</code> and <code>.catch()</code>.</p>
<h3>Callback vs Promise — error handling comparison</h3>
<pre><code class="language-js">// Callbacks — error check at every level
getUser(id, (err, user) =&gt; {
  if (err) { handleError(err); return; }
  getOrders(user.id, (err, orders) =&gt; {
    if (err) { handleError(err); return; }
    getDetails(orders[0].id, (err, details) =&gt; {
      if (err) { handleError(err); return; }
      render(details);
    });
  });
});

// Promises — one catch handles all
getUser(id)
  .then(user    =&gt; getOrders(user.id))
  .then(orders  =&gt; getDetails(orders[0].id))
  .then(details =&gt; render(details))
  .catch(err    =&gt; handleError(err));
</code></pre>
<p>In the callback version, the error check pattern <code>if (err) { handle; return; }</code> repeats three times. In the Promise version, one <code>.catch()</code> at the end handles any rejection from any step in the chain.</p>
<hr />
<h2>Promise Chaining</h2>
<p>This is where Promises show their real value over callbacks. When <code>.then()</code> returns a value, it is wrapped in a new fulfilled Promise. When it returns a Promise, the chain waits for that Promise to settle before continuing. This is what makes chaining work.</p>
<pre><code class="language-js">fetchUser(1)
  .then(user =&gt; {
    return fetchOrders(user.id); // returns a Promise
  })
  .then(orders =&gt; {
    return fetchDetails(orders[0].id); // returns a Promise
  })
  .then(details =&gt; {
    console.log("Final result:", details);
  })
  .catch(err =&gt; {
    console.log("Any step failed:", err.message);
  });
</code></pre>
<p>Each <code>.then()</code> receives the resolved value of the previous step. If any step rejects, the chain skips all remaining <code>.then()</code> calls and goes directly to <code>.catch()</code>.</p>
<h3>Returning plain values in a chain</h3>
<p>You can also return plain values (not Promises) from <code>.then()</code>. They are wrapped in a resolved Promise automatically:</p>
<pre><code class="language-js">fetchUser(1)
  .then(user =&gt; user.id)        // returns a number — wrapped in Promise.resolve(1)
  .then(id =&gt; `User #${id}`)    // returns a string — wrapped automatically
  .then(label =&gt; console.log(label)); // "User #1"
</code></pre>
<p>This lets you transform values between async steps without starting new async operations.</p>
<h3>A real-world chain</h3>
<pre><code class="language-js">function loadProfile(userId) {
  return fetchUser(userId)
    .then(user =&gt; {
      return fetchPosts(user.id).then(posts =&gt; ({ user, posts }));
    })
    .then(({ user, posts }) =&gt; {
      return fetchComments(posts[0].id).then(comments =&gt; ({
        user,
        posts,
        comments
      }));
    })
    .then(data =&gt; {
      renderProfile(data);
      return data;
    })
    .catch(err =&gt; {
      showError("Could not load profile.");
      console.error(err);
      return null;
    });
}
</code></pre>
<p>Each step depends on the previous. Variables from earlier steps stay accessible inside the nested <code>.then()</code> calls. One <code>.catch()</code> at the end handles any failure in the entire sequence.</p>
<hr />
<h2>Utility Methods</h2>
<h3><code>Promise.all()</code> — run in parallel, wait for all</h3>
<pre><code class="language-js">Promise.all([
  fetchUser(1),
  fetchPosts(),
  fetchNotifications()
]).then(([user, posts, notifications]) =&gt; {
  render({ user, posts, notifications });
}).catch(err =&gt; {
  console.log("One of the requests failed:", err.message);
});
</code></pre>
<p>All three requests start simultaneously. The <code>.then()</code> runs when all three resolve. If any one rejects, the <code>.catch()</code> runs immediately with that rejection reason.</p>
<h3><code>Promise.allSettled()</code> — run in parallel, handle each outcome</h3>
<pre><code class="language-js">Promise.allSettled([
  fetchUser(1),
  fetchPosts(),
  fetchNotifications()
]).then(results =&gt; {
  results.forEach(result =&gt; {
    if (result.status === "fulfilled") {
      console.log("Value:", result.value);
    } else {
      console.log("Error:", result.reason.message);
    }
  });
});
</code></pre>
<p>Unlike <code>Promise.all</code>, <code>Promise.allSettled</code> waits for every Promise to settle — fulfilled or rejected — and gives you the outcome of each. Nothing is skipped.</p>
<h3><code>Promise.race()</code> — first settled wins</h3>
<pre><code class="language-js">Promise.race([
  fetchFromPrimaryServer(),
  fetchFromBackupServer()
]).then(result =&gt; {
  console.log("Fastest response:", result);
});
</code></pre>
<p>Resolves or rejects with the outcome of whichever Promise settles first. Useful for timeouts and fallback strategies.</p>
<h3><code>Promise.resolve()</code> and <code>Promise.reject()</code></h3>
<p>These create already-settled Promises:</p>
<pre><code class="language-js">Promise.resolve(42).then(val =&gt; console.log(val)); // 42
Promise.reject(new Error("fail")).catch(err =&gt; console.log(err.message)); // fail
</code></pre>
<p>Useful for returning consistent Promise-based values from functions that may or may not do async work.</p>
<hr />
<h2>Common Mistakes</h2>
<p><strong>Forgetting to return in a chain:</strong></p>
<pre><code class="language-js">// Wrong — the chain does not wait for fetchOrders
fetchUser(1)
  .then(user =&gt; {
    fetchOrders(user.id); // missing return
  })
  .then(orders =&gt; {
    console.log(orders); // undefined — previous step returned nothing
  });

// Correct
fetchUser(1)
  .then(user =&gt; fetchOrders(user.id)) // return the Promise
  .then(orders =&gt; console.log(orders));
</code></pre>
<p>Without <code>return</code>, <code>.then()</code> resolves with <code>undefined</code> immediately instead of waiting for the inner Promise.</p>
<p><strong>Creating a new Promise when one already exists:</strong></p>
<pre><code class="language-js">// Unnecessary wrapper
function getUser(id) {
  return new Promise((resolve, reject) =&gt; {
    fetch(`/api/users/${id}`)
      .then(r =&gt; r.json())
      .then(data =&gt; resolve(data))
      .catch(err =&gt; reject(err));
  });
}

// Simpler — fetch already returns a Promise
function getUser(id) {
  return fetch(`/api/users/${id}`).then(r =&gt; r.json());
}
</code></pre>
<p>Wrapping a Promise in another Promise is called the explicit Promise construction antipattern. Since <code>fetch</code> already returns a Promise, just return the chain directly.</p>
<hr />
<h2>Wrapping Up</h2>
<p>Promises are the foundation of modern asynchronous JavaScript. They solve the structural problems of callbacks — the nesting, the scattered error handling, the scope barriers between steps — by giving you a linear, chainable interface for async operations.</p>
<p>The three states — pending, fulfilled, rejected — map directly to the lifecycle of any async operation. <code>.then()</code> handles success. <code>.catch()</code> handles failure. <code>.finally()</code> handles cleanup. Chaining connects multiple async steps so they read in the order they execute.</p>
<p><code>async/await</code> — which you may already know — is built entirely on Promises. Every <code>async</code> function returns a Promise. Every <code>await</code> expression waits for one. Understanding how Promises work makes <code>async/await</code> entirely predictable rather than partially magical.</p>
]]></content:encoded></item><item><title><![CDATA[Destructuring in JavaScript: Extract Values Without the Repetition]]></title><description><![CDATA[There is a pattern every JavaScript developer writes constantly:
const name = user.name;
const age = user.age;
const city = user.city;

Three lines. Three assignments. Three times you write the variab]]></description><link>https://blogs.arnabsamanta.in/destructuring-in-javascript-extract-values-without-the-repetition</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/destructuring-in-javascript-extract-values-without-the-repetition</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 05:26:47 GMT</pubDate><content:encoded><![CDATA[<p>There is a pattern every JavaScript developer writes constantly:</p>
<pre><code class="language-js">const name = user.name;
const age = user.age;
const city = user.city;
</code></pre>
<p>Three lines. Three assignments. Three times you write the variable name. For a complex object with six or eight fields, this becomes tedious and visually cluttered. Destructuring replaces all of it with a single, expressive line.</p>
<p>Destructuring is a syntax for unpacking values from arrays or properties from objects into individual variables. It was introduced in ES6, and once you get comfortable with it, the old way of extracting values feels unnecessarily verbose.</p>
<hr />
<h2>What Destructuring Means</h2>
<p>Destructuring means pulling values out of a data structure and assigning them to named variables — in one step, matching the structure of the data on the left side of the assignment.</p>
<p>The mental model is simple: the left side of the <code>=</code> is a <em>pattern</em> that mirrors the shape of the data on the right side. JavaScript reads that pattern and extracts the matching values.</p>
<pre><code class="language-js">// Before destructuring — extract manually
const user = { name: "Priya", age: 28 };
const name = user.name;
const age  = user.age;

// After destructuring — extract by pattern
const { name, age } = user;
</code></pre>
<p>Both produce the same <code>name</code> and <code>age</code> variables. The destructuring version does it in one line, by describing what you want rather than how to get it.</p>
<hr />
<h2>Destructuring Arrays</h2>
<p>Array destructuring extracts values by <em>position</em>. The variable on the left maps to the element at the same index on the right.</p>
<pre><code class="language-js">const colors = ["red", "green", "blue"];

const [first, second, third] = colors;

console.log(first);  // "red"
console.log(second); // "green"
console.log(third);  // "blue"
</code></pre>
<p>The brackets <code>[]</code> on the left are the pattern. The first variable gets index <code>0</code>, the second gets index <code>1</code>, and so on.</p>
<h3>Before vs after</h3>
<pre><code class="language-js">// Before
const rgb = [255, 128, 0];
const red   = rgb[0];
const green = rgb[1];
const blue  = rgb[2];

// After
const [red, green, blue] = [255, 128, 0];
</code></pre>
<p>The after version reads like English — "red, green, and blue come from this array."</p>
<h3>Skipping elements</h3>
<p>You can skip positions by leaving an empty slot:</p>
<pre><code class="language-js">const scores = [91, 78, 85, 62, 94];

const [first, , third, , fifth] = scores;

console.log(first); // 91
console.log(third); // 85
console.log(fifth); // 94
</code></pre>
<p>Commas with no variable in between skip that index. You only extract what you need.</p>
<h3>Swapping variables</h3>
<p>One of the cleanest applications of array destructuring is swapping two variables without a temporary:</p>
<pre><code class="language-js">// Before — required a temp variable
let a = 1, b = 2;
const temp = a;
a = b;
b = temp;

// After — one line
let a = 1, b = 2;
[a, b] = [b, a];

console.log(a); // 2
console.log(b); // 1
</code></pre>
<h3>Rest in array destructuring</h3>
<p>You can capture remaining elements using <code>...rest</code>:</p>
<pre><code class="language-js">const [head, ...tail] = [10, 20, 30, 40, 50];

console.log(head); // 10
console.log(tail); // [20, 30, 40, 50]
</code></pre>
<p><code>tail</code> is always an array — even if there is only one element left, or none.</p>
<h3>Destructuring function return values</h3>
<p>When a function returns an array, destructuring makes consuming it clean:</p>
<pre><code class="language-js">function getMinMax(numbers) {
  return [Math.min(...numbers), Math.max(...numbers)];
}

const [min, max] = getMinMax([4, 1, 9, 3, 7]);

console.log(min); // 1
console.log(max); // 9
</code></pre>
<p>This is why functions like <code>useState</code> in React return arrays — so you can name the values whatever you like:</p>
<pre><code class="language-js">const [count, setCount] = useState(0);
const [name, setName]   = useState("");
</code></pre>
<hr />
<h2>Destructuring Objects</h2>
<p>Object destructuring extracts properties by <em>name</em>. The variable name on the left must match the property name on the right.</p>
<pre><code class="language-js">const user = {
  name: "Rahul",
  age: 34,
  city: "Bengaluru"
};

const { name, age, city } = user;

console.log(name); // "Rahul"
console.log(age);  // 34
console.log(city); // "Bengaluru"
</code></pre>
<h3>Before vs after</h3>
<pre><code class="language-js">const product = {
  id: "P001",
  title: "Mechanical Keyboard",
  price: 3500,
  inStock: true
};

// Before
const id      = product.id;
const title   = product.title;
const price   = product.price;
const inStock = product.inStock;

// After
const { id, title, price, inStock } = product;
</code></pre>
<p>Four lines become one. The intent is clearer — you are describing <em>which</em> properties you want, not <em>how</em> to reach each one.</p>
<h3>Renaming while destructuring</h3>
<p>If the property name does not suit your local context, you can rename it:</p>
<pre><code class="language-js">const response = {
  data: { name: "Priya" },
  status: 200,
  ok: true
};

const { data: user, status: httpStatus, ok: success } = response;

console.log(user);       // { name: "Priya" }
console.log(httpStatus); // 200
console.log(success);    // true
</code></pre>
<p>The syntax is <code>{ propertyName: localVariableName }</code>. The property <code>data</code> is extracted into a variable called <code>user</code>. The original property name <code>data</code> is not available as a variable — only <code>user</code> is.</p>
<h3>Nested object destructuring</h3>
<p>Objects inside objects can be destructured in the same pattern:</p>
<pre><code class="language-js">const employee = {
  name: "Ananya",
  role: "engineer",
  address: {
    city: "Mumbai",
    pincode: "400001"
  }
};

const { name, address: { city, pincode } } = employee;

console.log(name);    // "Ananya"
console.log(city);    // "Mumbai"
console.log(pincode); // "400001"
</code></pre>
<p>The nested <code>address: { city, pincode }</code> pattern goes one level deeper. Note that <code>address</code> itself is not available as a variable — you extracted its contents, not the object.</p>
<p>If you need both the nested object <em>and</em> its contents:</p>
<pre><code class="language-js">const { address, address: { city } } = employee;
// address = { city: "Mumbai", pincode: "400001" }
// city = "Mumbai"
</code></pre>
<h3>Rest in object destructuring</h3>
<p>Like arrays, you can collect remaining properties into a new object:</p>
<pre><code class="language-js">const user = { name: "Priya", age: 28, role: "admin", active: true };

const { name, role, ...rest } = user;

console.log(name); // "Priya"
console.log(role); // "admin"
console.log(rest); // { age: 28, active: true }
</code></pre>
<p><code>rest</code> is a new object with the properties that were not explicitly named. This is a clean way to "pick" specific properties from an object without mutating it.</p>
<h3>Destructuring in function parameters</h3>
<p>One of the most common uses of object destructuring is directly in function parameters. Instead of receiving an entire object and accessing its properties manually, you extract what you need in the signature:</p>
<pre><code class="language-js">// Before
function createCard(product) {
  return `\({product.title} — Rs. \){product.price}`;
}

// After
function createCard({ title, price }) {
  return `\({title} — Rs. \){price}`;
}

createCard({ title: "Keyboard", price: 3500, inStock: true });
// "Keyboard — Rs. 3500"
</code></pre>
<p>The function body is simpler. The function signature documents exactly which properties it uses. Extra properties on the passed object are silently ignored.</p>
<p>This pattern is extremely common in React component props:</p>
<pre><code class="language-js">function UserCard({ name, avatar, bio }) {
  return (
    &lt;div&gt;
      &lt;img src={avatar} alt={name} /&gt;
      &lt;h2&gt;{name}&lt;/h2&gt;
      &lt;p&gt;{bio}&lt;/p&gt;
    &lt;/div&gt;
  );
}
</code></pre>
<hr />
<h2>Default Values</h2>
<p>When a destructured variable does not exist in the source data — or is <code>undefined</code> — you can provide a default value. The default is used only when the value would otherwise be <code>undefined</code>. It is not used for <code>null</code> or <code>0</code> or <code>false</code>.</p>
<h3>Default values in array destructuring</h3>
<pre><code class="language-js">const [x = 10, y = 20, z = 30] = [1, 2];

console.log(x); // 1  — from array
console.log(y); // 2  — from array
console.log(z); // 30 — default, no third element
</code></pre>
<h3>Default values in object destructuring</h3>
<pre><code class="language-js">const settings = {
  theme: "dark",
  language: "en"
};

const { theme = "light", language = "en", fontSize = 14 } = settings;

console.log(theme);    // "dark"  — from object
console.log(language); // "en"    — from object
console.log(fontSize); // 14      — default, not in object
</code></pre>
<p><code>fontSize</code> is not in <code>settings</code>, so it falls back to <code>14</code>.</p>
<h3>Defaults with renaming</h3>
<p>You can combine renaming and defaults:</p>
<pre><code class="language-js">const config = { timeout: 5000 };

const { timeout: requestTimeout = 3000, retries: maxRetries = 3 } = config;

console.log(requestTimeout); // 5000 — from object (renamed)
console.log(maxRetries);     // 3    — default (not in object)
</code></pre>
<p><code>timeout</code> is renamed to <code>requestTimeout</code> and found in the object, so the default does not apply. <code>retries</code> is renamed to <code>maxRetries</code> and not found, so the default <code>3</code> is used.</p>
<h3>Defaults in function parameters</h3>
<p>Combined with function parameter destructuring, defaults let you write functions that accept partial option objects:</p>
<pre><code class="language-js">function createRequest({ method = "GET", timeout = 5000, retry = true } = {}) {
  return { method, timeout, retry };
}

createRequest({ method: "POST" });
// { method: "POST", timeout: 5000, retry: true }

createRequest();
// { method: "GET", timeout: 5000, retry: true }
</code></pre>
<p>The <code>= {}</code> at the end provides a default for the entire parameter, so calling <code>createRequest()</code> with no argument does not throw. Inside, each property has its own default. The caller only needs to provide the values they want to override.</p>
<hr />
<h2>Practical Patterns</h2>
<h3>Destructuring API responses</h3>
<pre><code class="language-js">async function loadUser(id) {
  const response = await fetch(`/api/users/${id}`);
  const { name, email, role, createdAt } = await response.json();

  console.log(`\({name} (\){role}) — ${email}`);
}
</code></pre>
<p>The destructuring immediately extracts what the function needs from the response. Properties not listed are ignored.</p>
<h3>Extracting from arrays of objects</h3>
<pre><code class="language-js">const users = [
  { name: "Priya", score: 95 },
  { name: "Rahul", score: 88 },
  { name: "Ananya", score: 92 }
];

users.forEach(({ name, score }) =&gt; {
  console.log(`\({name}: \){score}`);
});
// Priya: 95
// Rahul: 88
// Ananya: 92
</code></pre>
<p>The destructuring happens directly in the <code>forEach</code> callback parameter. No <code>user.name</code> or <code>user.score</code> anywhere.</p>
<h3>Destructuring in loops</h3>
<pre><code class="language-js">const entries = [["name", "Priya"], ["age", 28], ["city", "Mumbai"]];

for (const [key, value] of entries) {
  console.log(`\({key}: \){value}`);
}
// name: Priya
// age: 28
// city: Mumbai
</code></pre>
<p>This is also the pattern behind <code>Object.entries()</code>:</p>
<pre><code class="language-js">const user = { name: "Priya", age: 28, city: "Mumbai" };

for (const [key, value] of Object.entries(user)) {
  console.log(`\({key}: \){value}`);
}
</code></pre>
<h3>Selective imports in ES modules</h3>
<p>Module imports use the same destructuring syntax — pulling only what you need from a module:</p>
<pre><code class="language-js">import { useState, useEffect, useRef } from "react";
import { formatDate, formatCurrency } from "./utils";
</code></pre>
<p>This is not coincidence. ES module named imports follow the same pattern as object destructuring — extracting named exports by their exact name.</p>
<hr />
<h2>Benefits of Destructuring</h2>
<p><strong>Less repetition.</strong> You write each property name once. With manual extraction, you write it twice — once to access it and once to name the variable. For a six-property object, destructuring saves six redundant lookups.</p>
<p><strong>Cleaner code.</strong> Destructuring communicates intent directly. <code>const { name, role } = user</code> reads as "I need the name and role from user." <code>const name = user.name; const role = user.role;</code> reads as a series of mechanical steps.</p>
<p><strong>Self-documenting function signatures.</strong> When a function uses parameter destructuring, the signature itself tells you which properties it consumes — no need to read the function body to find out what it expects from its argument.</p>
<p><strong>Safer defaults.</strong> Default values in destructuring are co-located with the extraction. You can see at a glance what values are optional and what falls back to if they are missing — without separate <code>if</code> checks or <code>|| defaultValue</code> expressions scattered through the function body.</p>
<p><strong>Works naturally with modern patterns.</strong> React props, ES module imports, <code>Object.entries()</code> loops, <code>useState</code>, API response handling — destructuring fits all of these naturally. It is not a novelty feature; it is a core part of how modern JavaScript is written.</p>
<hr />
<h2>Quick Reference</h2>
<pre><code class="language-js">// Array destructuring
const [a, b, c] = [1, 2, 3];
const [first, , third] = arr;          // skip elements
const [head, ...tail] = arr;           // rest
const [x = 0, y = 0] = [5];           // defaults

// Object destructuring
const { name, age } = user;
const { name: fullName } = user;       // rename
const { address: { city } } = user;   // nested
const { ...rest } = user;             // rest
const { role = "viewer" } = user;     // default

// Function parameter destructuring
function fn({ name, age = 18 }) { }
function fn([first, second]) { }

// Swap
[a, b] = [b, a];
</code></pre>
<hr />
<h2>Wrapping Up</h2>
<p>Destructuring is one of those features that seems like a convenience until you realise it changes how you think about extracting data. Instead of writing a series of assignment statements that mechanically pull values out, you write a pattern that describes the shape of what you want.</p>
<p>The result is code that is shorter, more readable, and easier to change. Renaming is explicit. Defaults are co-located. The structure of the data is visible in the variable declarations themselves.</p>
<p>Start with the simple patterns — basic object and array destructuring — and let the rest follow naturally. Within a week of using it consistently, the old <code>const name = user.name</code> style will feel unnecessarily repetitive.</p>
]]></content:encoded></item><item><title><![CDATA[Synchronous vs Asynchronous JavaScript: How Code Actually Executes]]></title><description><![CDATA[Before you can truly understand Promises, async/await, or event listeners, you need to understand one more fundamental thing: how JavaScript decides when to run your code.
Most of the time, JavaScript]]></description><link>https://blogs.arnabsamanta.in/synchronous-vs-asynchronous-javascript-how-code-actually-executes</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/synchronous-vs-asynchronous-javascript-how-code-actually-executes</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 05:23:41 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/35920be5-c9a9-4499-8424-8c86ca6030c1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before you can truly understand Promises, async/await, or event listeners, you need to understand one more fundamental thing: how JavaScript decides <em>when</em> to run your code.</p>
<p>Most of the time, JavaScript runs your code the way you would expect — one line, then the next, then the next. That is synchronous execution. But some operations take time — fetching data from a server, reading a file, waiting for a user to click. If JavaScript had to wait for each of those before moving on, every app would freeze constantly.</p>
<p>Asynchronous code is JavaScript's answer to that problem. Understanding the difference between the two — and <em>why</em> the difference exists — is what makes the rest of async JavaScript make sense.</p>
<hr />
<h2>What Synchronous Code Means</h2>
<p>Synchronous means one thing at a time, in order. Each line of code runs completely before the next one starts. If a line takes a long time, everything else waits.</p>
<pre><code class="language-js">console.log("Step 1: Start");
console.log("Step 2: Middle");
console.log("Step 3: End");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Step 1: Start
Step 2: Middle
Step 3: End
</code></pre>
<p>No surprises. Line 1 finishes, then line 2 runs, then line 3. The order in the output matches the order in the code exactly.</p>
<p>This is how most programming works in everyday contexts — a recipe, a to-do list, a set of instructions. Do step one completely. Then step two. Then step three.</p>
<h3>A synchronous function call</h3>
<pre><code class="language-js">function greet(name) {
  const message = `Hello, ${name}!`;
  return message;
}

const result = greet("Priya");
console.log(result);
console.log("Done");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Hello, Priya!
Done
</code></pre>
<p>When <code>greet("Priya")</code> is called, JavaScript enters the function, runs every line inside it, and returns the result. Only then does the next line (<code>console.log(result)</code>) run. The function call <em>blocks</em> everything else until it finishes.</p>
<p>For fast operations like this one, blocking is not a problem. The function runs in microseconds. No one notices the wait.</p>
<p>The problem comes when an operation takes real time.</p>
<hr />
<h2>The Problem with Blocking Code</h2>
<p>Imagine you need to fetch a user's profile from a server. The request might take 500ms, or 2 seconds, or more — depending on the network, the server load, the response size.</p>
<p>In a purely synchronous world, that looks like this:</p>
<pre><code class="language-js">console.log("Loading profile...");
const profile = fetchProfileSync("https://api.example.com/user/1");
// JavaScript freezes here for 2 seconds
console.log("Profile loaded:", profile.name);
console.log("Page is ready");
</code></pre>
<p>During those 2 seconds — while <code>fetchProfileSync</code> is running — <em>nothing else happens</em>. The browser cannot respond to clicks. Animations freeze. The scroll bar stops. Input fields do not register keystrokes. From the user's perspective, the page is completely unresponsive.</p>
<p>This is called <strong>blocking code</strong>: code that stops everything else from running until it finishes.</p>
<h3>A restaurant analogy</h3>
<p>Think of a restaurant with one waiter (the JavaScript thread). In a synchronous model, the waiter takes an order, walks to the kitchen, stands at the counter and waits for the food to be prepared, then brings it back to the table. While waiting at the kitchen, every other table in the restaurant is completely ignored. No drinks refilled. No menus handed out. No bills processed.</p>
<p>That waiter would get terrible reviews.</p>
<p>In an asynchronous model, the waiter takes an order, hands it to the kitchen, then immediately goes to attend to other tables. When the kitchen finishes the food, they notify the waiter, who then delivers it. The waiter is never idle, and no table is neglected.</p>
<p>JavaScript works the same way — and it learned this lesson early.</p>
<hr />
<h2>What Asynchronous Code Means</h2>
<p>Asynchronous means that some operations are <em>started</em> and then <em>deferred</em> — JavaScript kicks them off, moves on to the next line of code, and handles the result when it arrives later.</p>
<pre><code class="language-js">console.log("1: Before fetch");

setTimeout(function() {
  console.log("3: Inside timeout");
}, 2000);

console.log("2: After fetch");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">1: Before fetch
2: After fetch
3: Inside timeout   (appears 2 seconds later)
</code></pre>
<p><code>setTimeout</code> does not pause JavaScript for 2 seconds. It registers a task to run after 2 seconds and immediately returns. JavaScript continues to the next line. Two seconds later, when the timer fires, the callback runs.</p>
<p>The order of the output does not match the order of the code — and that is the key difference from synchronous execution. Line 3 in the source code runs <em>after</em> line 4 in the output's time.</p>
<h3>What "non-blocking" means</h3>
<p>Non-blocking code starts an operation and does not wait for it to finish before moving on. The operation runs in the background (handled by the browser or Node.js runtime), and your code is notified when it is done.</p>
<pre><code class="language-js">// Non-blocking — does not freeze the page
fetch("https://api.example.com/user/1")
  .then(response =&gt; response.json())
  .then(user =&gt; console.log("User:", user.name));

console.log("This runs immediately, before the user data arrives");
</code></pre>
<p>The <code>fetch</code> call starts the network request and returns a Promise immediately. JavaScript does not wait for the response. It runs the next <code>console.log</code> right away. When the response eventually arrives, the <code>.then()</code> callbacks run.</p>
<hr />
<h2>Why JavaScript Needs Asynchronous Behavior</h2>
<p>JavaScript is single-threaded. There is one call stack, one thread of execution. Unlike languages that can spawn multiple threads to handle concurrent work, JavaScript does everything on a single thread.</p>
<p>This is not a flaw — it is a deliberate design choice that makes JavaScript simpler to reason about (no race conditions, no deadlocks). But it means that if any operation takes a long time and blocks the thread, everything stops.</p>
<p>The operations that take meaningful time are:</p>
<ul>
<li><p><strong>Network requests</strong> — fetching data from APIs, loading resources</p>
</li>
<li><p><strong>File system operations</strong> — reading or writing files (mainly in Node.js)</p>
</li>
<li><p><strong>Timers</strong> — <code>setTimeout</code>, <code>setInterval</code></p>
</li>
<li><p><strong>User events</strong> — waiting for clicks, keypresses, form submissions</p>
</li>
<li><p><strong>Database queries</strong> — reading from or writing to a database</p>
</li>
</ul>
<p>None of these have predictable or controllable duration. A network request might take 100ms or 5 seconds. A user might click a button immediately or never. JavaScript cannot afford to block the thread waiting for any of them.</p>
<p>The solution is to handle them asynchronously — start the operation, register a function to run when it completes, and move on.</p>
<hr />
<h2>Examples: API Calls and Timers</h2>
<h3>Timers</h3>
<p><code>setTimeout</code> and <code>setInterval</code> are the simplest examples of asynchronous behavior:</p>
<pre><code class="language-js">console.log("Start");

setTimeout(() =&gt; {
  console.log("This runs after 1 second");
}, 1000);

setTimeout(() =&gt; {
  console.log("This runs after 0 seconds");
}, 0);

console.log("End");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Start
End
This runs after 0 seconds   (after all synchronous code finishes)
This runs after 1 second    (1 second after script started)
</code></pre>
<p>Even <code>setTimeout(fn, 0)</code> does not run the callback immediately. It waits for all synchronous code to finish first. The <code>0</code> means "as soon as possible after the current synchronous work is done" — not "right now."</p>
<p>This reveals something important: asynchronous callbacks never interrupt synchronous code. They always wait in a queue until the synchronous code finishes.</p>
<h3>API calls</h3>
<pre><code class="language-js">console.log("Fetching user...");

fetch("https://api.example.com/users/1")
  .then(response =&gt; response.json())
  .then(user =&gt; {
    console.log("User received:", user.name);
  });

console.log("Fetch started, moving on");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Fetching user...
Fetch started, moving on
User received: Priya      (arrives whenever the server responds)
</code></pre>
<p>The <code>fetch</code> call starts the HTTP request and returns immediately. JavaScript does not stand at the network waiting for bytes to arrive. It moves to the next statement. When the response eventually arrives, the <code>.then()</code> callbacks run.</p>
<h3>Multiple async operations running concurrently</h3>
<p>Because asynchronous operations do not block the thread, multiple can run at the same time:</p>
<pre><code class="language-js">console.log("Starting requests");

fetch("/api/users").then(r =&gt; r.json()).then(data =&gt; {
  console.log("Users loaded:", data.length);
});

fetch("/api/posts").then(r =&gt; r.json()).then(data =&gt; {
  console.log("Posts loaded:", data.length);
});

fetch("/api/comments").then(r =&gt; r.json()).then(data =&gt; {
  console.log("Comments loaded:", data.length);
});

console.log("All requests started");
</code></pre>
<p>All three network requests are in flight simultaneously. Whichever server responds first, that callback runs first. The total time is roughly the duration of the slowest request — not the sum of all three.</p>
<p>In a synchronous world, this would take (time for users) + (time for posts) + (time for comments). In an asynchronous world, it takes max(time for users, time for posts, time for comments).</p>
<hr />
<h2>How JavaScript Handles This: The Event Loop</h2>
<p>Understanding <em>why</em> async behavior works the way it does requires knowing about the event loop — the mechanism that makes it all possible.</p>
<p>JavaScript has three key components:</p>
<p><strong>The call stack</strong> is where your synchronous code runs. Functions are pushed onto the stack when called and popped off when they return. Only one thing runs at a time.</p>
<p><strong>The Web APIs / Node APIs</strong> are where async operations actually happen — the browser or Node.js runtime handles timers, network requests, and file reads outside of the JavaScript thread. When the operation completes, it sends the callback to the next component.</p>
<p><strong>The callback queue (task queue)</strong> is where completed async callbacks wait. When the call stack is empty — when all synchronous code has finished — the event loop picks the next callback from the queue and pushes it onto the stack to run.</p>
<pre><code class="language-plaintext">Call Stack          Web APIs             Callback Queue
──────────          ────────             ──────────────
main()         →   setTimeout (2000ms)
console.log()       fetch (network)
...                 setInterval
(finishes)                          →   [callback waiting]
                                         ↓ (event loop picks it up)
                                    → Call Stack runs callback
</code></pre>
<p>This is why <code>setTimeout(fn, 0)</code> still waits for synchronous code to finish. The callback goes to the queue, and the queue is only processed when the call stack is empty.</p>
<h3>Microtasks: where Promises queue</h3>
<p>Promise callbacks (<code>.then()</code>, <code>.catch()</code>, <code>async/await</code>) go into a <em>microtask queue</em>, which has higher priority than the regular callback queue. Microtasks are processed after every task, before any new task from the queue runs.</p>
<pre><code class="language-js">console.log("1: sync start");

setTimeout(() =&gt; console.log("4: setTimeout callback"), 0);

Promise.resolve().then(() =&gt; console.log("3: promise callback"));

console.log("2: sync end");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">1: sync start
2: sync end
3: promise callback      (microtask — runs before setTimeout)
4: setTimeout callback   (regular task — runs after microtasks)
</code></pre>
<p>Promise callbacks always run before timer callbacks, even when the timer has a zero delay. This is why the async/await examples earlier in this series behave consistently — Promise resolution is processed in a predictable, high-priority queue.</p>
<hr />
<h2>Synchronous vs Asynchronous: A Direct Comparison</h2>
<table>
<thead>
<tr>
<th></th>
<th>Synchronous</th>
<th>Asynchronous</th>
</tr>
</thead>
<tbody><tr>
<td>Execution</td>
<td>Line by line, in order</td>
<td>Some tasks deferred until completion</td>
</tr>
<tr>
<td>Blocking</td>
<td>Yes — next line waits</td>
<td>No — continues immediately</td>
</tr>
<tr>
<td>Output order</td>
<td>Matches code order</td>
<td>May differ from code order</td>
</tr>
<tr>
<td>Use case</td>
<td>Fast calculations, data transforms</td>
<td>Network, timers, file I/O, events</td>
</tr>
<tr>
<td>Risk</td>
<td>Freezes UI for slow operations</td>
<td>Requires careful error handling</td>
</tr>
</tbody></table>
<hr />
<h2>Real Consequences of Blocking Code</h2>
<p>Blocking in a browser does not just mean "slow." It means the page literally becomes unresponsive. The browser cannot repaint, cannot respond to input, cannot run any other JavaScript. Users see a frozen page.</p>
<p>Here is a demonstration of what blocking looks like:</p>
<pre><code class="language-js">// Simulates a slow synchronous operation
function blockFor(ms) {
  const start = Date.now();
  while (Date.now() - start &lt; ms) {
    // burning CPU time
  }
}

document.getElementById("btn").addEventListener("click", () =&gt; {
  console.log("Button clicked");
  blockFor(3000); // blocks for 3 seconds
  console.log("Done blocking");
});
</code></pre>
<p>When the button is clicked, <code>blockFor(3000)</code> runs. For three full seconds, the browser cannot do anything — no scrolling, no other clicks, no animations. The <code>console.log("Done blocking")</code> only appears after those three seconds.</p>
<p>This is why CPU-intensive work (image processing, data crunching, encryption) should be moved to Web Workers — separate threads that can run heavy computation without blocking the main thread.</p>
<p>Compare that to the non-blocking version using a timer:</p>
<pre><code class="language-js">document.getElementById("btn").addEventListener("click", () =&gt; {
  console.log("Button clicked — starting task");

  setTimeout(() =&gt; {
    console.log("Task complete"); // runs after 3 seconds, without blocking
  }, 3000);

  console.log("Button handler finished — page remains responsive");
});
</code></pre>
<p>The page remains fully interactive during those 3 seconds because the timer callback is deferred. The work happens outside the main thread.</p>
<hr />
<h2>Blocking vs Non-Blocking in Node.js</h2>
<p>In Node.js — where JavaScript runs on servers — blocking is even more damaging. A Node.js server handles all client requests on a single thread. If one request triggers a blocking operation, every other client waiting for a response is stalled.</p>
<pre><code class="language-js">// Blocking file read — freezes the server for every client
const fs = require("fs");

app.get("/file", (req, res) =&gt; {
  const data = fs.readFileSync("large-file.txt"); // blocks
  res.send(data);
});

// Non-blocking file read — server remains responsive
app.get("/file", (req, res) =&gt; {
  fs.readFile("large-file.txt", (err, data) =&gt; { // non-blocking
    if (err) return res.status(500).send("Error");
    res.send(data);
  });
});
</code></pre>
<p>In the synchronous version, the server stops handling all other requests while the file is being read. In the asynchronous version, it starts reading the file, moves on to handle other requests, and sends the response when the file is ready.</p>
<p>This is why Node.js is built almost entirely on asynchronous APIs. It is designed around the non-blocking model.</p>
<hr />
<h2>When to Use Each</h2>
<p><strong>Use synchronous code for:</strong></p>
<ul>
<li><p>Calculations and data transformations that happen in memory</p>
</li>
<li><p>Reading values from variables</p>
</li>
<li><p>Any operation that completes in microseconds and has no I/O</p>
</li>
<li><p>Code that depends strictly on the result of the previous line</p>
</li>
</ul>
<p><strong>Use asynchronous code for:</strong></p>
<ul>
<li><p>Any network request</p>
</li>
<li><p>File system reads and writes</p>
</li>
<li><p>Timers and scheduled tasks</p>
</li>
<li><p>Database queries</p>
</li>
<li><p>Any operation whose duration you cannot control</p>
</li>
</ul>
<p>The practical rule is straightforward: if the operation involves waiting for something outside your JavaScript code, it should be asynchronous.</p>
<hr />
<h2>Wrapping Up</h2>
<p>Synchronous code is predictable and simple — one line at a time, in order. But that simplicity becomes a liability the moment any line takes noticeable time. A single slow synchronous operation freezes everything.</p>
<p>Asynchronous code solves this by decoupling the <em>start</em> of an operation from the <em>handling of its result</em>. JavaScript starts the operation, moves on, and handles the result when it arrives — keeping the thread free to do other work in the meantime.</p>
<p>The event loop is the mechanism that makes this coordination possible. Synchronous code runs first, completely. Microtasks (Promise callbacks) run next. Macrotasks (timers, I/O callbacks) run after. That ordering is what makes the execution of async code predictable once you understand the model.</p>
<p>Callbacks, Promises, and async/await are all different syntaxes for expressing the same idea: "start this, and when it finishes, do that." Understanding synchronous vs asynchronous execution is what makes all three of those patterns make sense.</p>
]]></content:encoded></item><item><title><![CDATA[Async/Await in JavaScript: Writing Asynchronous Code That Reads Like Synchronous Code]]></title><description><![CDATA[JavaScript's async story has evolved through three phases. First came callbacks — functions passed to be called later. Then came Promises — objects representing a future value, chainable with .then().]]></description><link>https://blogs.arnabsamanta.in/async-await-in-javascript-writing-asynchronous-code-that-reads-like-synchronous-code</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/async-await-in-javascript-writing-asynchronous-code-that-reads-like-synchronous-code</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 04:52:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/94004f8d-4695-4236-b26d-dbdd8a1ee787.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JavaScript's async story has evolved through three phases. First came callbacks — functions passed to be called later. Then came Promises — objects representing a future value, chainable with <code>.then()</code>. Then came <code>async/await</code> — syntax that lets you write asynchronous code that reads almost exactly like synchronous code.</p>
<p><code>async/await</code> did not replace Promises. It is built on top of them. Every <code>async</code> function returns a Promise. Every <code>await</code> expression pauses and waits for a Promise. But the way you write and read that code changes dramatically — and that is the point.</p>
<hr />
<h2>Why async/await Was Introduced</h2>
<p>Promises improved on callbacks significantly. Instead of nesting functions inside functions, you chain <code>.then()</code> calls in sequence:</p>
<pre><code class="language-js">// Callbacks — nested, hard to follow
getUser(id, function(err, user) {
  if (err) return handleError(err);
  getOrders(user.id, function(err, orders) {
    if (err) return handleError(err);
    getOrderDetails(orders[0].id, function(err, details) {
      if (err) return handleError(err);
      console.log(details);
    });
  });
});

// Promises — chained, better
getUser(id)
  .then(user =&gt; getOrders(user.id))
  .then(orders =&gt; getOrderDetails(orders[0].id))
  .then(details =&gt; console.log(details))
  .catch(err =&gt; handleError(err));
</code></pre>
<p>The Promise chain is already a large improvement. But it still has friction. The <code>.then()</code> wrapper around each step is visual noise. The variable from one step cannot easily be referenced in a later step without extra contortions. Error handling with <code>.catch()</code> applies to the whole chain, making it harder to handle specific failures differently.</p>
<p><code>async/await</code> solves the remaining friction:</p>
<pre><code class="language-js">// async/await — reads like synchronous code
async function loadOrderDetails(id) {
  try {
    const user = await getUser(id);
    const orders = await getOrders(user.id);
    const details = await getOrderDetails(orders[0].id);
    console.log(details);
  } catch (err) {
    handleError(err);
  }
}
</code></pre>
<p>The logic is identical. The Promise mechanics are unchanged underneath. But the code reads top to bottom, variables are accessible anywhere in the block, and error handling uses <code>try...catch</code> — the same pattern used for synchronous errors. There is no new mental model to learn. The existing one extends naturally.</p>
<hr />
<h2>How async Functions Work</h2>
<p>The <code>async</code> keyword before a function declaration changes two things: it makes the function return a Promise, and it allows the <code>await</code> keyword to be used inside it.</p>
<pre><code class="language-js">async function greet() {
  return "Hello, Priya!";
}

greet(); // returns a Promise
greet().then(msg =&gt; console.log(msg)); // Hello, Priya!
</code></pre>
<p>Even though <code>greet</code> returns a plain string, <code>async</code> wraps it in a resolved Promise automatically. Returning a value from an <code>async</code> function is equivalent to <code>Promise.resolve(value)</code>.</p>
<p>If you explicitly return a Promise from an <code>async</code> function, it is not double-wrapped — the Promise is returned as-is:</p>
<pre><code class="language-js">async function fetchData() {
  return Promise.resolve(42);
}

fetchData().then(val =&gt; console.log(val)); // 42 — not Promise.resolve(Promise.resolve(42))
</code></pre>
<p><code>async</code> functions can be written in any function form:</p>
<pre><code class="language-js">// Function declaration
async function fetchUser(id) { ... }

// Function expression
const fetchUser = async function(id) { ... }

// Arrow function
const fetchUser = async (id) =&gt; { ... }

// Method in a class or object
class UserService {
  async getUser(id) { ... }
}
</code></pre>
<p>The keyword always goes before the <code>function</code> keyword or parameter list. For arrow functions, it goes before the parameters.</p>
<h3>What happens when an async function throws</h3>
<p>If an <code>async</code> function throws an error (or returns a rejected Promise), the returned Promise is rejected with that error:</p>
<pre><code class="language-js">async function fail() {
  throw new Error("Something went wrong");
}

fail().catch(err =&gt; console.log(err.message)); // Something went wrong
</code></pre>
<p>This is the Promise equivalent of <code>Promise.reject(new Error("..."))</code>. Uncaught rejections in <code>async</code> functions behave exactly like uncaught Promise rejections.</p>
<hr />
<h2>The <code>await</code> Keyword</h2>
<p><code>await</code> can only be used inside an <code>async</code> function (or at the top level of an ES module). It pauses execution of the <code>async</code> function until the Promise it precedes is settled — either resolved or rejected — and then resumes.</p>
<pre><code class="language-js">async function example() {
  console.log("1. Before await");
  const result = await Promise.resolve("hello");
  console.log("2. After await:", result);
  console.log("3. Done");
}

example();
console.log("4. After calling example()");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">1. Before await
4. After calling example()
2. After await: hello
3. Done
</code></pre>
<p>This output is the key to understanding <code>await</code>. When <code>example()</code> is called, it runs until it hits <code>await</code>. At that point, it suspends — it yields control back to the surrounding code. <code>"4. After calling example()"</code> runs while <code>example</code> is paused. When the awaited Promise resolves, <code>example</code> resumes from where it left off.</p>
<p>The function does not block the thread. It pauses <em>itself</em>, not JavaScript. Other code continues to run while the async operation completes.</p>
<h3><code>await</code> unwraps the Promise value</h3>
<p>The expression <code>await promise</code> evaluates to the resolved value of the Promise — not the Promise itself:</p>
<pre><code class="language-js">async function getNumber() {
  const value = await Promise.resolve(42);
  console.log(value); // 42 — not Promise { 42 }
  return value;
}
</code></pre>
<p>Without <code>await</code>, you would have a Promise object. With <code>await</code>, you have the value inside it. This is the main ergonomic benefit — you work with values directly rather than always wrapping and unwrapping them.</p>
<h3><code>await</code> with non-Promise values</h3>
<p>You can <code>await</code> any value. If the value is not a Promise, <code>await</code> treats it as an already-resolved Promise and continues immediately:</p>
<pre><code class="language-js">async function example() {
  const x = await 42;     // immediately resolves
  const y = await "hello"; // same
  console.log(x, y); // 42  hello
}
</code></pre>
<p>This is useful in functions that accept either a value or a Promise — you can <code>await</code> the argument without special-casing it.</p>
<hr />
<h2>Sequential vs Parallel Execution</h2>
<p>One of the most important things to understand about <code>await</code> is that awaiting each operation in sequence means they run one after the other — the next one does not start until the previous one finishes.</p>
<pre><code class="language-js">async function sequential() {
  const a = await fetchA(); // waits for fetchA to finish
  const b = await fetchB(); // only then starts fetchB
  return [a, b];
}
</code></pre>
<p>If <code>fetchA</code> and <code>fetchB</code> are independent, this wastes time. They could run in parallel. To run them concurrently, start both Promises before awaiting either:</p>
<pre><code class="language-js">async function parallel() {
  const promiseA = fetchA(); // starts immediately
  const promiseB = fetchB(); // starts immediately, does not wait for A

  const a = await promiseA; // waits for A
  const b = await promiseB; // waits for B (may already be done)
  return [a, b];
}
</code></pre>
<p>Or more cleanly with <code>Promise.all</code>:</p>
<pre><code class="language-js">async function parallel() {
  const [a, b] = await Promise.all([fetchA(), fetchB()]);
  return [a, b];
}
</code></pre>
<p><code>Promise.all</code> takes an array of Promises, runs them concurrently, and resolves when all of them resolve. If any one rejects, <code>Promise.all</code> rejects immediately with that reason.</p>
<p>Sequential <code>await</code> is correct when each step depends on the result of the previous. Parallel <code>Promise.all</code> is correct when steps are independent.</p>
<hr />
<h2>Error Handling with async Code</h2>
<p>Error handling in <code>async/await</code> uses standard <code>try...catch</code> blocks. When an awaited Promise rejects, it throws at the <code>await</code> expression — exactly like a synchronous throw.</p>
<pre><code class="language-js">async function fetchUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`);

    if (!response.ok) {
      throw new Error(`HTTP ${response.status}: could not fetch user`);
    }

    const user = await response.json();
    return user;
  } catch (error) {
    console.error("Failed to fetch user:", error.message);
    return null;
  }
}
</code></pre>
<p>The <code>try...catch</code> wraps all the await expressions together. If <code>fetch</code> rejects (network error), or if <code>response.json()</code> throws (malformed JSON), or if you explicitly throw, all of it is caught in the same <code>catch</code> block.</p>
<h3>Handling specific operations differently</h3>
<p>If you need different handling for different steps, use separate <code>try...catch</code> blocks:</p>
<pre><code class="language-js">async function loadDashboard(userId) {
  let user;
  try {
    user = await fetchUser(userId);
  } catch {
    return showError("Could not load your account.");
  }

  try {
    const data = await fetchDashboardData(user.id);
    render(data);
  } catch {
    render(getDefaultDashboard()); // fallback — still show something
  }
}
</code></pre>
<p>The first error is fatal — if we cannot identify the user, there is nothing to show. The second error has a fallback — the dashboard can still render with default data.</p>
<h3>The <code>.catch()</code> alternative</h3>
<p>You can also handle errors on the Promise returned by the <code>async</code> function:</p>
<pre><code class="language-js">async function fetchUser(id) {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}

fetchUser(1)
  .then(user =&gt; console.log(user))
  .catch(err =&gt; console.error(err));
</code></pre>
<p>Or attach <code>.catch()</code> to individual awaited Promises for per-operation fallbacks:</p>
<pre><code class="language-js">async function loadPage() {
  const user = await fetchUser(id).catch(() =&gt; null);
  const posts = await fetchPosts().catch(() =&gt; []);

  if (!user) return showLoginPage();
  render(user, posts);
}
</code></pre>
<p>This pattern — <code>await promise.catch(() =&gt; defaultValue)</code> — gives each operation a fallback without nesting <code>try...catch</code> blocks everywhere.</p>
<hr />
<h2>async/await vs Promises: A Direct Comparison</h2>
<p>The two styles express the same logic. Here is the same sequence of dependent async operations written both ways:</p>
<h3>With Promises</h3>
<pre><code class="language-js">function loadUserProfile(userId) {
  return getUser(userId)
    .then(user =&gt; {
      return getPosts(user.id).then(posts =&gt; {
        return getComments(posts[0].id).then(comments =&gt; {
          return { user, posts, comments };
        });
      });
    })
    .catch(err =&gt; {
      console.error("Failed to load profile:", err);
      return null;
    });
}
</code></pre>
<p>The nesting creeps back in as soon as you need a value from one step in a later step. <code>user</code> is available in the outer <code>.then</code>, but <code>posts</code> is not available in the same scope as <code>comments</code> unless you nest them.</p>
<p>You can flatten this with intermediate variables, but it gets verbose:</p>
<pre><code class="language-js">function loadUserProfile(userId) {
  let savedUser;
  let savedPosts;

  return getUser(userId)
    .then(user =&gt; { savedUser = user; return getPosts(user.id); })
    .then(posts =&gt; { savedPosts = posts; return getComments(posts[0].id); })
    .then(comments =&gt; ({ user: savedUser, posts: savedPosts, comments }))
    .catch(err =&gt; { console.error("Failed:", err); return null; });
}
</code></pre>
<p>The intermediate variables (<code>savedUser</code>, <code>savedPosts</code>) are pollution that exists only to bridge the scope gap between <code>.then()</code> calls.</p>
<h3>With async/await</h3>
<pre><code class="language-js">async function loadUserProfile(userId) {
  try {
    const user = await getUser(userId);
    const posts = await getPosts(user.id);
    const comments = await getComments(posts[0].id);
    return { user, posts, comments };
  } catch (err) {
    console.error("Failed to load profile:", err);
    return null;
  }
}
</code></pre>
<p>All variables are in the same scope. No intermediate storage. No nesting. The logic reads exactly as it would if these operations were synchronous. The <code>try...catch</code> handles all errors in one place.</p>
<h3>Summary comparison</h3>
<table>
<thead>
<tr>
<th>Aspect</th>
<th>Promises</th>
<th>async/await</th>
</tr>
</thead>
<tbody><tr>
<td>Syntax</td>
<td><code>.then()</code> chains</td>
<td><code>await</code> expressions</td>
</tr>
<tr>
<td>Readability</td>
<td>Good for simple chains</td>
<td>Better for sequential logic</td>
</tr>
<tr>
<td>Variable scope</td>
<td>Each <code>.then()</code> has its own scope</td>
<td>All in the same block</td>
</tr>
<tr>
<td>Error handling</td>
<td><code>.catch()</code> at end of chain</td>
<td><code>try...catch</code> blocks</td>
</tr>
<tr>
<td>Debugging</td>
<td>Stack traces can be incomplete</td>
<td>Cleaner stack traces</td>
</tr>
<tr>
<td>Parallel operations</td>
<td><code>Promise.all()</code></td>
<td><code>await Promise.all()</code></td>
</tr>
<tr>
<td>Return value</td>
<td>Promise</td>
<td>Promise (async function returns one)</td>
</tr>
</tbody></table>
<p>They are not mutually exclusive. Real code often uses both — <code>async/await</code> for the main flow and <code>Promise.all</code> or <code>.catch()</code> where they fit more naturally.</p>
<hr />
<h2>Practical Examples</h2>
<h3>Fetching data with async/await</h3>
<pre><code class="language-js">async function getWeather(city) {
  const url = `https://api.weather.example.com/city/${city}`;

  const response = await fetch(url);

  if (!response.ok) {
    throw new Error(`Could not fetch weather for ${city}`);
  }

  const data = await response.json();
  return data;
}

async function displayWeather() {
  try {
    const weather = await getWeather("Mumbai");
    console.log(`Temperature: ${weather.temp}°C`);
    console.log(`Condition: ${weather.description}`);
  } catch (error) {
    console.log("Unable to load weather:", error.message);
  }
}

displayWeather();
</code></pre>
<h3>Loading multiple resources in parallel</h3>
<pre><code class="language-js">async function loadPageData(userId) {
  try {
    const [profile, feed, notifications] = await Promise.all([
      fetchProfile(userId),
      fetchFeed(userId),
      fetchNotifications(userId)
    ]);

    return { profile, feed, notifications };
  } catch (error) {
    console.error("Failed to load page data:", error);
    return null;
  }
}
</code></pre>
<p>All three requests fire at the same time. The function waits until all three complete before continuing. If any one fails, the whole operation is treated as a failure.</p>
<h3>Retry logic with async/await</h3>
<pre><code class="language-js">async function fetchWithRetry(url, retries = 3) {
  for (let attempt = 1; attempt &lt;= retries; attempt++) {
    try {
      const response = await fetch(url);
      if (!response.ok) throw new Error(`HTTP ${response.status}`);
      return await response.json();
    } catch (error) {
      if (attempt === retries) throw error;
      console.log(`Attempt ${attempt} failed. Retrying...`);
      await new Promise(resolve =&gt; setTimeout(resolve, 1000 * attempt));
    }
  }
}
</code></pre>
<p><code>await new Promise(resolve =&gt; setTimeout(resolve, delay))</code> is the async/await way to wait for a fixed duration. The retry logic reads naturally as a loop — something that would be significantly harder to express cleanly with Promise chains.</p>
<hr />
<h2>Common Pitfalls</h2>
<p><strong>Forgetting</strong> <code>await</code><strong>:</strong></p>
<pre><code class="language-js">async function fetchUser(id) {
  const response = fetch(`/api/users/${id}`); // missing await
  return response.json(); // error: response is a Promise, not a Response
}
</code></pre>
<p>Without <code>await</code>, <code>response</code> is the Promise itself, not the resolved value. The <code>.json()</code> call fails because Promise objects do not have that method. The error message is confusing and the cause is not obvious. This is one of the most common async bugs.</p>
<p><strong>Using</strong> <code>await</code> <strong>in a regular forEach loop:</strong></p>
<pre><code class="language-js">// This does not work as expected
async function processAll(ids) {
  ids.forEach(async (id) =&gt; {
    const user = await fetchUser(id); // awaited inside the callback, not the outer function
    console.log(user);
  });
  console.log("Done"); // prints before any user is logged
}
</code></pre>
<p><code>forEach</code> does not await its callback. Each iteration starts an async operation and moves on immediately. Use <code>for...of</code> when you need sequential awaiting, or <code>Promise.all</code> for parallel:</p>
<pre><code class="language-js">// Sequential
async function processAll(ids) {
  for (const id of ids) {
    const user = await fetchUser(id);
    console.log(user);
  }
}

// Parallel
async function processAll(ids) {
  const users = await Promise.all(ids.map(id =&gt; fetchUser(id)));
  users.forEach(user =&gt; console.log(user));
}
</code></pre>
<p><strong>Not handling rejections:</strong></p>
<pre><code class="language-js">async function load() {
  const data = await fetch("/api/data"); // rejection goes unhandled
  return data.json();
}

load(); // if this rejects, it's an unhandled Promise rejection
</code></pre>
<p>Every <code>async</code> function call should be wrapped in <code>try...catch</code>, or have <code>.catch()</code> attached to it. Unhandled Promise rejections surface as warnings in Node.js and may crash the process in future versions.</p>
<hr />
<h2>Wrapping Up</h2>
<p><code>async/await</code> is the current standard for writing asynchronous JavaScript. It is syntactic sugar over Promises — the execution model is identical, but the code you write is dramatically more readable. Sequential operations look sequential. Variables are in scope where you use them. Error handling is standard <code>try...catch</code>.</p>
<p>The core rules are simple:</p>
<ul>
<li><p>Mark a function <code>async</code> to return a Promise and use <code>await</code> inside it</p>
</li>
<li><p><code>await</code> pauses the function, not the thread</p>
</li>
<li><p>Sequential <code>await</code> runs operations one after the other; <code>Promise.all</code> runs them in parallel</p>
</li>
<li><p>Wrap awaited operations in <code>try...catch</code> to handle failures</p>
</li>
</ul>
<p>Understanding that <code>async/await</code> is built on Promises — not separate from them — is what lets you use both comfortably. Some situations call for <code>Promise.all</code>, <code>Promise.race</code>, or <code>.catch()</code> chaining. Most sequential async logic is cleaner with <code>await</code>. The two styles are complementary, and fluency with both is what real-world async code requires.</p>
]]></content:encoded></item><item><title><![CDATA[Map and Set in JavaScript: Better Data Structures for the Right Problems]]></title><description><![CDATA[JavaScript has always had objects for key-value storage and arrays for ordered collections. They are versatile and familiar, but they come with real limitations that bite you in specific situations. M]]></description><link>https://blogs.arnabsamanta.in/map-and-set-in-javascript-better-data-structures-for-the-right-problems</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/map-and-set-in-javascript-better-data-structures-for-the-right-problems</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 04:49:21 GMT</pubDate><content:encoded><![CDATA[<p>JavaScript has always had objects for key-value storage and arrays for ordered collections. They are versatile and familiar, but they come with real limitations that bite you in specific situations. <code>Map</code> and <code>Set</code> — introduced in ES6 — were designed to fill exactly those gaps.</p>
<p>This article covers what <code>Map</code> and <code>Set</code> are, how they differ from their traditional counterparts, and the specific situations where reaching for them produces cleaner, more correct code.</p>
<hr />
<h2>The Problems with Traditional Objects and Arrays</h2>
<p>Before looking at what <code>Map</code> and <code>Set</code> offer, it helps to understand the pain points they address.</p>
<h3>Objects as key-value stores have hidden constraints</h3>
<pre><code class="language-js">const store = {};

store["name"] = "Priya";
store[1] = "one";
store[true] = "bool value";

console.log(Object.keys(store));
// ["1", "name", "true"]
</code></pre>
<p>Every key in an object is coerced to a string. The number <code>1</code> becomes <code>"1"</code>. The boolean <code>true</code> becomes <code>"true"</code>. If you need non-string keys — objects, functions, DOM nodes — a plain object cannot do it. You lose the original type completely.</p>
<p>Objects also carry inherited properties from <code>Object.prototype</code>:</p>
<pre><code class="language-js">const counts = {};
console.log("toString" in counts); // true — inherited, not yours
console.log("constructor" in counts); // true
</code></pre>
<p>If someone passes a key that happens to collide with a prototype property, you get unexpected behaviour. Getting the size of an object requires <code>Object.keys(obj).length</code> — there is no built-in <code>.size</code> property. And the insertion order of keys was not guaranteed until ES2015, and even then only for string keys.</p>
<h3>Arrays allow duplicates and linear searches</h3>
<pre><code class="language-js">const tags = ["javascript", "web", "javascript", "es6"];
console.log(tags.length); // 4 — duplicate exists
</code></pre>
<p>If you use an array as a collection of unique items, you have to enforce uniqueness manually. Checking whether a value exists requires <code>.includes()</code>, which is O(n) — it scans every element. For small arrays this is fine, but for large ones it becomes a bottleneck.</p>
<p><code>Map</code> and <code>Set</code> exist to solve these specific problems cleanly.</p>
<hr />
<h2>What Is Map?</h2>
<p>A <code>Map</code> is a collection of key-value pairs where the keys can be of any type — including objects, functions, and primitives. It remembers the insertion order of its entries and provides direct methods for getting, setting, checking, and deleting entries.</p>
<pre><code class="language-js">const map = new Map();

map.set("name", "Priya");
map.set(42, "the answer");
map.set(true, "boolean key");

const objKey = { id: 1 };
map.set(objKey, "object as key");

console.log(map.get("name"));  // "Priya"
console.log(map.get(42));      // "the answer"
console.log(map.get(objKey));  // "object as key"
console.log(map.size);         // 4
</code></pre>
<p>No type coercion. <code>42</code> stays <code>42</code> as a key, not <code>"42"</code>. An object reference used as a key maps to exactly that object — no collision with string keys, no prototype interference.</p>
<h3>Creating a Map</h3>
<p>You can initialize a <code>Map</code> from an array of <code>[key, value]</code> pairs:</p>
<pre><code class="language-js">const user = new Map([
  ["name", "Rahul"],
  ["age", 34],
  ["city", "Bengaluru"]
]);

console.log(user.get("name")); // "Rahul"
console.log(user.size);        // 3
</code></pre>
<h3>Core Map methods</h3>
<pre><code class="language-js">const m = new Map();

m.set("key", "value");   // add or update
m.get("key");            // "value"
m.has("key");            // true
m.delete("key");         // removes the entry, returns true
m.clear();               // removes all entries
m.size;                  // number of entries (not a method — a property)
</code></pre>
<h3>Iterating over a Map</h3>
<p>Maps maintain insertion order, and they are directly iterable:</p>
<pre><code class="language-js">const scores = new Map([
  ["Priya", 95],
  ["Rahul", 88],
  ["Ananya", 92]
]);

for (const [name, score] of scores) {
  console.log(`\({name}: \){score}`);
}
// Priya: 95
// Rahul: 88
// Ananya: 92

scores.forEach((score, name) =&gt; {
  console.log(`\({name}: \){score}`);
});

console.log([...scores.keys()]);   // ["Priya", "Rahul", "Ananya"]
console.log([...scores.values()]); // [95, 88, 92]
console.log([...scores.entries()]); // [["Priya", 95], ...]
</code></pre>
<p>Note the argument order in <code>forEach</code>: the value comes first, then the key. This matches the convention of other iterator callbacks (<code>value, key</code>) rather than the more intuitive <code>key, value</code>. It is a minor quirk worth remembering.</p>
<hr />
<h2>What Is Set?</h2>
<p>A <code>Set</code> is a collection of unique values. Any value you add that already exists in the <code>Set</code> is silently ignored. Like <code>Map</code>, it maintains insertion order and accepts values of any type.</p>
<pre><code class="language-js">const set = new Set();

set.add(1);
set.add(2);
set.add(2); // duplicate — ignored
set.add(3);
set.add("hello");

console.log(set.size); // 4
console.log(set.has(2)); // true
console.log(set.has(5)); // false
</code></pre>
<p>The duplicate <code>2</code> does not throw an error — it is simply not added. The <code>Set</code> always contains only distinct values.</p>
<h3>Creating a Set</h3>
<p>You can initialize a <code>Set</code> from any iterable:</p>
<pre><code class="language-js">const nums = new Set([1, 2, 3, 2, 1]);
console.log(nums.size); // 3 — duplicates removed

const letters = new Set("hello");
console.log([...letters]); // ["h", "e", "l", "o"] — duplicate "l" removed
</code></pre>
<h3>Core Set methods</h3>
<pre><code class="language-js">const s = new Set();

s.add("value");       // add a value
s.has("value");       // true
s.delete("value");    // removes, returns true
s.clear();            // removes all values
s.size;               // number of values
</code></pre>
<h3>Iterating over a Set</h3>
<pre><code class="language-js">const fruits = new Set(["mango", "banana", "guava", "mango"]);

for (const fruit of fruits) {
  console.log(fruit);
}
// mango
// banana
// guava

fruits.forEach(fruit =&gt; console.log(fruit));

console.log([...fruits]); // ["mango", "banana", "guava"]
</code></pre>
<p>Sets are iterable, so spread and <code>for...of</code> work directly. The order is the order of first insertion.</p>
<hr />
<h2>Map vs Object: Key Differences</h2>
<table>
<thead>
<tr>
<th></th>
<th>Object</th>
<th>Map</th>
</tr>
</thead>
<tbody><tr>
<td>Key types</td>
<td>Strings and Symbols only (others coerced to string)</td>
<td>Any value — objects, functions, primitives</td>
</tr>
<tr>
<td>Prototype keys</td>
<td>Inherits keys from <code>Object.prototype</code></td>
<td>No inherited keys</td>
</tr>
<tr>
<td>Size</td>
<td><code>Object.keys(obj).length</code></td>
<td><code>map.size</code></td>
</tr>
<tr>
<td>Iteration order</td>
<td>Not guaranteed for all key types</td>
<td>Always insertion order</td>
</tr>
<tr>
<td>Performance</td>
<td>Good for small, static key sets</td>
<td>Better for frequent additions and deletions</td>
</tr>
<tr>
<td>Serialization</td>
<td><code>JSON.stringify</code> works natively</td>
<td>Requires manual conversion</td>
</tr>
</tbody></table>
<h3>When the difference in key type matters</h3>
<pre><code class="language-js">// Object — DOM node as key fails
const cache = {};
const element = document.querySelector("#btn");
cache[element] = "clicked"; // key becomes "[object HTMLButtonElement]"

// Map — DOM node as key works perfectly
const cache = new Map();
cache.set(element, "clicked"); // key is the exact element reference
cache.get(element); // "clicked"
</code></pre>
<p>Caching computed values keyed by DOM elements, request objects, or any non-string value — this is exactly where <code>Map</code> shines and plain objects fail.</p>
<h3>When object size matters</h3>
<pre><code class="language-js">const obj = { a: 1, b: 2, c: 3 };
const size = Object.keys(obj).length; // 3 — extra work required

const map = new Map([["a", 1], ["b", 2], ["c", 3]]);
const size = map.size; // 3 — directly available
</code></pre>
<p>For frequently-counted collections, <code>map.size</code> is meaningfully more convenient.</p>
<h3>Prototype key collision — a real bug</h3>
<pre><code class="language-js">const wordCounts = {};

const words = ["constructor", "toString", "hasOwnProperty"];
words.forEach(word =&gt; {
  wordCounts[word] = (wordCounts[word] || 0) + 1;
});

console.log(wordCounts["toString"]); // 1 — works, but shadowing prototype methods
console.log("toString" in wordCounts); // true — ambiguous
</code></pre>
<p>Using <code>Map</code> eliminates any possibility of collision:</p>
<pre><code class="language-js">const wordCounts = new Map();
words.forEach(word =&gt; {
  wordCounts.set(word, (wordCounts.get(word) || 0) + 1);
});
// No prototype interference — ever
</code></pre>
<hr />
<h2>Set vs Array: Key Differences</h2>
<table>
<thead>
<tr>
<th></th>
<th>Array</th>
<th>Set</th>
</tr>
</thead>
<tbody><tr>
<td>Uniqueness</td>
<td>Allows duplicates</td>
<td>Only unique values</td>
</tr>
<tr>
<td>Membership check</td>
<td><code>arr.includes(val)</code> — O(n)</td>
<td><code>set.has(val)</code> — O(1)</td>
</tr>
<tr>
<td>Removing duplicates</td>
<td>Manual filtering required</td>
<td>Automatic</td>
</tr>
<tr>
<td>Index access</td>
<td><code>arr[0]</code>, <code>arr[1]</code>, etc.</td>
<td>Not supported</td>
</tr>
<tr>
<td>Built-in set operations</td>
<td>None</td>
<td>Manual (union, intersection, difference)</td>
</tr>
<tr>
<td>Order</td>
<td>Insertion order preserved</td>
<td>Insertion order preserved</td>
</tr>
</tbody></table>
<h3>The membership check performance gap</h3>
<p>For large collections, the difference between O(n) and O(1) membership testing is significant:</p>
<pre><code class="language-js">const items = Array.from({ length: 100000 }, (_, i) =&gt; i);
const itemArray = items;
const itemSet = new Set(items);

// Array: scans up to 100,000 elements
itemArray.includes(99999); // O(n)

// Set: hash-based lookup
itemSet.has(99999); // O(1)
</code></pre>
<p>For a collection of ten items this does not matter. For a collection of a hundred thousand, it does.</p>
<h3>Deduplicating an array</h3>
<pre><code class="language-js">const tags = ["js", "web", "js", "es6", "web", "node"];

// Array — manual deduplication
const unique = tags.filter((tag, index) =&gt; tags.indexOf(tag) === index);

// Set — automatic
const unique = [...new Set(tags)];

console.log(unique); // ["js", "web", "es6", "node"]
</code></pre>
<p>The <code>Set</code> approach is two characters of meaningful syntax (<code>new Set(...)</code>) wrapped in spread. The array approach requires understanding that <code>indexOf</code> returns the first occurrence index, and filtering based on that.</p>
<h3>Set operations (union, intersection, difference)</h3>
<p>Arrays have no built-in set math. Sets make it straightforward:</p>
<pre><code class="language-js">const a = new Set([1, 2, 3, 4]);
const b = new Set([3, 4, 5, 6]);

// Union — all values from both sets
const union = new Set([...a, ...b]);
console.log([...union]); // [1, 2, 3, 4, 5, 6]

// Intersection — values in both sets
const intersection = new Set([...a].filter(x =&gt; b.has(x)));
console.log([...intersection]); // [3, 4]

// Difference — values in a but not in b
const difference = new Set([...a].filter(x =&gt; !b.has(x)));
console.log([...difference]); // [1, 2]
</code></pre>
<p>The intersection and difference patterns use the fact that <code>set.has()</code> is O(1) — making these operations O(n) rather than O(n²) if you were doing the same thing with arrays.</p>
<hr />
<h2>When to Use Map and Set</h2>
<h3>Use Map when:</h3>
<p><strong>Keys are not strings.</strong> If you need to key a collection by objects, DOM nodes, functions, or any non-string value, <code>Map</code> is the correct tool. Objects cannot do this correctly.</p>
<pre><code class="language-js">// Caching expensive computations by their input object
const resultCache = new Map();

function expensiveCalc(input) {
  if (resultCache.has(input)) return resultCache.get(input);
  const result = /* ... compute ... */ input.value * 2;
  resultCache.set(input, result);
  return result;
}
</code></pre>
<p><strong>You need the size directly.</strong> If you frequently check how many entries a collection has, <code>map.size</code> is simpler than <code>Object.keys(obj).length</code>.</p>
<p><strong>Insertion order matters and keys are dynamic.</strong> Maps always iterate in insertion order, with no surprises from inherited properties or numeric key reordering.</p>
<p><strong>Frequent additions and deletions.</strong> Maps are optimised for dynamic key-value storage. Objects are optimised for a fixed set of known string keys (like a record or config object).</p>
<h3>Use Set when:</h3>
<p><strong>You need a collection of unique values.</strong> Any time "this collection should not have duplicates" is a requirement, <code>Set</code> is the right structure. It enforces uniqueness for you.</p>
<pre><code class="language-js">// Track which user IDs have been processed
const processedIds = new Set();

function processUser(id) {
  if (processedIds.has(id)) return; // already done
  processedIds.add(id);
  // ... do the work
}
</code></pre>
<p><strong>You need fast membership testing.</strong> If you are checking <code>if (collection includes X)</code> frequently, <code>Set.has()</code> is O(1) vs <code>Array.includes()</code> O(n).</p>
<pre><code class="language-js">// A permission system — fast role checking
const allowedRoles = new Set(["admin", "editor", "moderator"]);

function canEdit(userRole) {
  return allowedRoles.has(userRole); // O(1)
}
</code></pre>
<p><strong>Deduplicating input.</strong> Whenever you receive data that might have duplicates and you need only the distinct values, converting through a <code>Set</code> is the idiomatic approach.</p>
<pre><code class="language-js">function uniqueSorted(arr) {
  return [...new Set(arr)].sort();
}

uniqueSorted([3, 1, 2, 1, 3, 2]); // [1, 2, 3]
</code></pre>
<h3>Keep using Object when:</h3>
<ul>
<li><p>Keys are known string names (a user record, a config object, a response body)</p>
</li>
<li><p>You need <code>JSON.stringify</code> or <code>JSON.parse</code> to work directly</p>
</li>
<li><p>You are defining a data shape with fixed fields</p>
</li>
</ul>
<h3>Keep using Array when:</h3>
<ul>
<li><p>Order matters and duplicates are valid</p>
</li>
<li><p>You need index-based access (<code>arr[0]</code>)</p>
</li>
<li><p>You need the full array method toolkit (<code>map</code>, <code>filter</code>, <code>reduce</code>, <code>sort</code>, <code>slice</code>)</p>
</li>
</ul>
<hr />
<h2>Converting Between Structures</h2>
<pre><code class="language-js">// Map → Object
const map = new Map([["a", 1], ["b", 2]]);
const obj = Object.fromEntries(map);
// { a: 1, b: 2 }

// Object → Map
const obj = { a: 1, b: 2 };
const map = new Map(Object.entries(obj));

// Set → Array
const set = new Set([1, 2, 3]);
const arr = [...set]; // or Array.from(set)

// Array → Set (deduplication)
const arr = [1, 2, 2, 3];
const set = new Set(arr);
</code></pre>
<p><code>Object.fromEntries</code> and <code>Object.entries</code> are the bridge between objects and maps. Spread and <code>Array.from</code> are the bridge between sets and arrays.</p>
<hr />
<h2>Wrapping Up</h2>
<p><code>Map</code> and <code>Set</code> are not replacements for objects and arrays — they are the right tools for problems that objects and arrays handle awkwardly.</p>
<p>Reach for <code>Map</code> when your keys are not strings, when you need an accurate <code>.size</code>, or when you need a clean key-value store with no prototype interference. Reach for <code>Set</code> when uniqueness matters, when you need O(1) membership testing, or when you are working with union, intersection, or difference operations.</p>
<p>Understanding which data structure fits the problem is a fundamental skill. In many situations, <code>Map</code> and <code>Set</code> are the precise fit that produces correct, readable, and efficient code where a plain object or array would require workarounds.</p>
]]></content:encoded></item><item><title><![CDATA[Error Handling in JavaScript: try, catch, finally, and Throwing Custom Errors]]></title><description><![CDATA[Every JavaScript program will encounter errors. The question is not whether errors happen — it is whether your code handles them deliberately or lets them crash everything.
This article covers the ful]]></description><link>https://blogs.arnabsamanta.in/error-handling-in-javascript-try-catch-finally-and-throwing-custom-errors</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/error-handling-in-javascript-try-catch-finally-and-throwing-custom-errors</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 04:46:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/7a151efd-ffc3-4568-bbf9-d4b02e71c590.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every JavaScript program will encounter errors. The question is not whether errors happen — it is whether your code handles them deliberately or lets them crash everything.</p>
<p>This article covers the full error handling toolkit: what errors are, how <code>try</code>, <code>catch</code>, and <code>finally</code> work, how to throw your own errors, and why treating error handling as a first-class concern makes your code more reliable and easier to debug.</p>
<hr />
<h2>What Errors Are in JavaScript</h2>
<p>An error in JavaScript is an object. When something goes wrong — a variable that does not exist, a function called on the wrong type, division by zero — JavaScript creates an <code>Error</code> object and throws it. If nothing catches it, the program crashes and the error appears in the console.</p>
<pre><code class="language-js">console.log(undeclaredVariable);
// ReferenceError: undeclaredVariable is not defined

null.toString();
// TypeError: Cannot read properties of null (reading 'toString')

decodeURIComponent("%");
// URIError: URI malformed
</code></pre>
<p>Each error has two important properties:</p>
<ul>
<li><p><code>name</code> — the type of error (<code>"ReferenceError"</code>, <code>"TypeError"</code>, etc.)</p>
</li>
<li><p><code>message</code> — a human-readable description of what went wrong</p>
</li>
</ul>
<pre><code class="language-js">try {
  null.toString();
} catch (err) {
  console.log(err.name);    // TypeError
  console.log(err.message); // Cannot read properties of null (reading 'toString')
}
</code></pre>
<h3>Built-in error types</h3>
<p>JavaScript has several built-in error constructors, each representing a different category of problem:</p>
<table>
<thead>
<tr>
<th>Error type</th>
<th>When it occurs</th>
</tr>
</thead>
<tbody><tr>
<td><code>Error</code></td>
<td>General-purpose base error</td>
</tr>
<tr>
<td><code>ReferenceError</code></td>
<td>Accessing an undeclared variable</td>
</tr>
<tr>
<td><code>TypeError</code></td>
<td>Operating on a value of the wrong type</td>
</tr>
<tr>
<td><code>SyntaxError</code></td>
<td>Malformed JavaScript (usually at parse time)</td>
</tr>
<tr>
<td><code>RangeError</code></td>
<td>Value outside an allowable range (e.g., <code>new Array(-1)</code>)</td>
</tr>
<tr>
<td><code>URIError</code></td>
<td>Malformed URI passed to <code>decodeURIComponent</code></td>
</tr>
<tr>
<td><code>EvalError</code></td>
<td>Problems related to <code>eval()</code></td>
</tr>
</tbody></table>
<p>In practice, <code>TypeError</code> and <code>ReferenceError</code> are the ones you will encounter most. Knowing the type of an error is the first clue about where and why it happened.</p>
<hr />
<h2>The <code>try</code> and <code>catch</code> Blocks</h2>
<p>The <code>try...catch</code> statement is how you intercept errors and handle them gracefully instead of letting them crash your program.</p>
<pre><code class="language-js">try {
  // code that might throw
} catch (error) {
  // code that runs if something goes wrong
}
</code></pre>
<p>JavaScript executes the code inside <code>try</code>. If any statement throws an error, execution immediately jumps to the <code>catch</code> block. The error object is passed to the <code>catch</code> block as the parameter you name (conventionally <code>error</code> or <code>err</code>).</p>
<h3>A simple example</h3>
<pre><code class="language-js">function parseJSON(text) {
  try {
    const data = JSON.parse(text);
    console.log("Parsed successfully:", data);
    return data;
  } catch (error) {
    console.log("Invalid JSON:", error.message);
    return null;
  }
}

parseJSON('{"name": "Priya"}'); // Parsed successfully: { name: "Priya" }
parseJSON("not valid json");    // Invalid JSON: Unexpected token 'o', "not valid json" is not valid JSON
</code></pre>
<p>Without <code>try...catch</code>, the second call would crash. With it, the error is caught, logged, and the function returns a sensible fallback value. The rest of your program continues running.</p>
<h3>Execution flow inside try...catch</h3>
<pre><code class="language-js">try {
  console.log("1. Before error");
  null.toString();              // throws TypeError
  console.log("2. After error"); // never runs
} catch (error) {
  console.log("3. In catch:", error.name); // runs
}

console.log("4. After try...catch"); // runs
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">1. Before error
3. In catch: TypeError
4. After try...catch
</code></pre>
<p>Once an error is thrown, execution inside <code>try</code> stops immediately. Lines after the throw are skipped. Control transfers to <code>catch</code>. After <code>catch</code> completes, execution continues normally after the entire <code>try...catch</code> block.</p>
<h3>Catching specific error types</h3>
<p>You can inspect the caught error to respond differently based on what went wrong:</p>
<pre><code class="language-js">function divide(a, b) {
  try {
    if (typeof a !== "number" || typeof b !== "number") {
      throw new TypeError("Both arguments must be numbers");
    }
    if (b === 0) {
      throw new RangeError("Cannot divide by zero");
    }
    return a / b;
  } catch (error) {
    if (error instanceof TypeError) {
      console.log("Type problem:", error.message);
    } else if (error instanceof RangeError) {
      console.log("Range problem:", error.message);
    } else {
      console.log("Unexpected error:", error.message);
    }
    return null;
  }
}

divide(10, 2);       // 5
divide(10, 0);       // Range problem: Cannot divide by zero
divide("10", 2);     // Type problem: Both arguments must be numbers
</code></pre>
<p><code>instanceof</code> checks whether the error is an instance of a specific error constructor. This pattern lets a single <code>catch</code> block handle multiple error types differently — without needing separate <code>try...catch</code> for each.</p>
<hr />
<h2>The <code>finally</code> Block</h2>
<p>The <code>finally</code> block runs after <code>try</code> and <code>catch</code>, regardless of what happened. It runs whether an error was thrown, whether it was caught, and whether the <code>try</code> block completed successfully. It even runs when a <code>return</code> statement appears inside <code>try</code> or <code>catch</code>.</p>
<pre><code class="language-js">try {
  // might throw
} catch (error) {
  // handles the error
} finally {
  // always runs
}
</code></pre>
<h3>A file-reading analogy</h3>
<p><code>finally</code> maps directly to the "clean up after yourself" principle. If you open a database connection or start a loading spinner, you need to close the connection or stop the spinner when the operation is done — whether it succeeded or failed.</p>
<pre><code class="language-js">function fetchUserData(userId) {
  showLoadingSpinner();

  try {
    const data = getFromDatabase(userId);
    displayUser(data);
    return data;
  } catch (error) {
    showErrorMessage("Could not load user data.");
    console.error(error);
  } finally {
    hideLoadingSpinner(); // always runs, no matter what
  }
}
</code></pre>
<p>If <code>getFromDatabase</code> throws, the error is caught and displayed. Either way, <code>hideLoadingSpinner</code> runs. Without <code>finally</code>, you would need to call <code>hideLoadingSpinner</code> in both <code>try</code> and <code>catch</code> — duplicating logic and risking a missed call if the code changes later.</p>
<h3><code>finally</code> with return statements</h3>
<p><code>finally</code> runs even when there is a <code>return</code> inside <code>try</code> or <code>catch</code>. If <code>finally</code> itself contains a <code>return</code>, it overrides the earlier return:</p>
<pre><code class="language-js">function example() {
  try {
    return "from try";
  } finally {
    console.log("finally ran");
    // no return here — "from try" is preserved
  }
}

console.log(example());
// finally ran
// from try
</code></pre>
<pre><code class="language-js">function example() {
  try {
    return "from try";
  } finally {
    return "from finally"; // overrides the return in try
  }
}

console.log(example()); // "from finally"
</code></pre>
<p>The second case is a behaviour to be aware of, but in practice, putting a <code>return</code> in <code>finally</code> is unusual and usually a mistake. Use <code>finally</code> for cleanup, not for controlling return values.</p>
<h3>Execution order summary</h3>
<pre><code class="language-js">function demo(shouldThrow) {
  try {
    console.log("try: start");
    if (shouldThrow) throw new Error("oops");
    console.log("try: end");
    return "success";
  } catch (err) {
    console.log("catch:", err.message);
    return "recovered";
  } finally {
    console.log("finally: always");
  }
}

console.log(demo(false));
// try: start
// try: end
// finally: always
// success

console.log(demo(true));
// try: start
// catch: oops
// finally: always
// recovered
</code></pre>
<p><code>finally</code> always gets the last word on cleanup, but the return value from <code>try</code> or <code>catch</code> is what the function returns — unless <code>finally</code> returns something itself.</p>
<hr />
<h2>Throwing Custom Errors</h2>
<p>You are not limited to errors that JavaScript throws automatically. You can throw your own errors using the <code>throw</code> statement.</p>
<pre><code class="language-js">throw new Error("Something went wrong");
</code></pre>
<p><code>throw</code> can technically accept any value — a string, a number, an object — but throwing an <code>Error</code> object is the right approach. It gives you a message, a stack trace, and a name, all of which are essential for debugging.</p>
<h3>Throwing with built-in error types</h3>
<pre><code class="language-js">function setAge(age) {
  if (typeof age !== "number") {
    throw new TypeError(`Expected a number, got ${typeof age}`);
  }
  if (age &lt; 0 || age &gt; 150) {
    throw new RangeError(`Age must be between 0 and 150, got ${age}`);
  }
  return age;
}

setAge(25);     // 25
setAge("old");  // TypeError: Expected a number, got string
setAge(-5);     // RangeError: Age must be between 0 and 150, got -5
</code></pre>
<p>Using the specific error constructor rather than the generic <code>Error</code> gives callers useful information about the nature of the problem.</p>
<h3>Creating custom error classes</h3>
<p>For application-specific errors, you can extend the built-in <code>Error</code> class to create your own error types. This lets callers use <code>instanceof</code> to distinguish your errors from generic ones.</p>
<pre><code class="language-js">class ValidationError extends Error {
  constructor(message, field) {
    super(message);
    this.name = "ValidationError";
    this.field = field;
  }
}

class NetworkError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.name = "NetworkError";
    this.statusCode = statusCode;
  }
}
</code></pre>
<p>Using them:</p>
<pre><code class="language-js">function validateUser(user) {
  if (!user.name) {
    throw new ValidationError("Name is required", "name");
  }
  if (!user.email.includes("@")) {
    throw new ValidationError("Invalid email format", "email");
  }
}

function loadUser(id) {
  try {
    validateUser({ name: "", email: "priya@example.com" });
  } catch (error) {
    if (error instanceof ValidationError) {
      console.log(`Validation failed on field '\({error.field}': \){error.message}`);
    } else {
      throw error; // re-throw errors we don't know how to handle
    }
  }
}

loadUser(1);
// Validation failed on field 'name': Name is required
</code></pre>
<p>Notice the re-throw pattern: <code>throw error</code> inside <code>catch</code>. When you catch an error and realise you cannot handle it at this level, re-throwing it passes the problem up the call stack to a handler that can deal with it. This avoids silently swallowing errors that should surface.</p>
<h3>The re-throw pattern</h3>
<pre><code class="language-js">function processPayment(amount) {
  try {
    chargeCard(amount);
  } catch (error) {
    if (error instanceof NetworkError) {
      console.log("Network issue, will retry later");
      scheduleRetry();
    } else {
      throw error; // not a network error — not our responsibility
    }
  }
}
</code></pre>
<p>Only catch what you can handle. Let the rest propagate.</p>
<hr />
<h2>Why Error Handling Matters</h2>
<h3>Graceful failure over silent failure</h3>
<p>Unhandled errors crash programs. But there is something worse than a crash: silent failure — code that encounters an error, does nothing about it, and continues with corrupted state.</p>
<pre><code class="language-js">// No error handling — silent failure
function getUserCity(user) {
  return user.address.city; // crashes if address is null
}

// With error handling — graceful failure
function getUserCity(user) {
  try {
    return user.address.city;
  } catch {
    return "Unknown";
  }
}
</code></pre>
<p>"Unknown" is a better outcome than a crash. The user sees a default; the application keeps running.</p>
<h3>Better debugging</h3>
<p>Error objects carry a stack trace — a list of function calls that led to the error. When you catch and log errors properly, debugging becomes straightforward:</p>
<pre><code class="language-js">try {
  processOrder(orderId);
} catch (error) {
  console.error("Order processing failed:", {
    message: error.message,
    stack: error.stack,
    orderId
  });
}
</code></pre>
<p>Logging <code>error.stack</code> shows exactly which line threw, which function called that, and how far up the chain the problem originated. Without it, you are guessing.</p>
<h3>User experience</h3>
<p>From a user's perspective, a crash is always worse than an error message. When your code handles errors and provides feedback, users understand what happened and what to do next:</p>
<pre><code class="language-js">async function submitForm(data) {
  try {
    await fetch("/api/submit", {
      method: "POST",
      body: JSON.stringify(data)
    });
    showSuccess("Form submitted successfully!");
  } catch (error) {
    if (error instanceof NetworkError) {
      showError("No internet connection. Please try again.");
    } else {
      showError("Something went wrong. Our team has been notified.");
      reportToMonitoring(error);
    }
  }
}
</code></pre>
<p>The user sees a meaningful message either way. The engineering team sees the error in monitoring. Nothing crashes silently.</p>
<h3>Defensive programming</h3>
<p>Good error handling is part of defensive programming — writing code that anticipates what can go wrong rather than assuming the happy path:</p>
<pre><code class="language-js">function parseConfig(raw) {
  if (!raw) {
    throw new ValidationError("Config cannot be empty", "config");
  }

  let parsed;
  try {
    parsed = JSON.parse(raw);
  } catch {
    throw new ValidationError("Config must be valid JSON", "config");
  }

  if (!parsed.apiKey) {
    throw new ValidationError("apiKey is required in config", "apiKey");
  }

  return parsed;
}
</code></pre>
<p>This function is explicit about what it requires and what it rejects. Every failure mode produces an informative error. Code that calls this function knows exactly what went wrong and can respond appropriately.</p>
<hr />
<h2>Error Handling with Async Code</h2>
<p><code>try...catch</code> works with <code>async/await</code> just as it does with synchronous code:</p>
<pre><code class="language-js">async function fetchUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`);

    if (!response.ok) {
      throw new NetworkError(`Request failed`, response.status);
    }

    const user = await response.json();
    return user;
  } catch (error) {
    if (error instanceof NetworkError) {
      console.log(`HTTP \({error.statusCode}: could not fetch user \){id}`);
    } else {
      console.error("Unexpected error:", error);
    }
    return null;
  }
}
</code></pre>
<p>Without <code>async/await</code>, Promises use <code>.catch()</code>:</p>
<pre><code class="language-js">fetch("/api/users/1")
  .then(response =&gt; response.json())
  .then(user =&gt; console.log(user))
  .catch(error =&gt; console.error("Fetch failed:", error));
</code></pre>
<p>Both patterns are valid. <code>async/await</code> with <code>try...catch</code> tends to be more readable for complex sequences of async operations.</p>
<hr />
<h2>Common Mistakes in Error Handling</h2>
<p><strong>Catching and doing nothing:</strong></p>
<pre><code class="language-js">// Bad — swallows the error silently
try {
  riskyOperation();
} catch (error) {
  // nothing
}
</code></pre>
<p>Empty <code>catch</code> blocks are the <code>// TODO: handle this</code> of error handling. If you are not ready to handle an error, at minimum log it.</p>
<p><strong>Catching errors you cannot handle:</strong></p>
<pre><code class="language-js">// Catching too broadly
try {
  // 50 lines of code
} catch (error) {
  console.log("Something went wrong");
}
</code></pre>
<p>A <code>try</code> block that wraps too much code makes it hard to know which operation failed. Narrow <code>try...catch</code> to the specific operations that can fail.</p>
<p><strong>Using</strong> <code>throw</code> <strong>without</strong> <code>Error</code> <strong>objects:</strong></p>
<pre><code class="language-js">// Bad — string throws lose the stack trace
throw "something went wrong";

// Good — proper Error object
throw new Error("something went wrong");
</code></pre>
<p>String throws do not have <code>.stack</code>, <code>.name</code>, or <code>.message</code>. They are harder to log, harder to inspect, and harder to catch specifically.</p>
<hr />
<h2>Wrapping Up</h2>
<p>Error handling in JavaScript is not a defensive afterthought — it is part of the design of reliable software. The tools are straightforward:</p>
<ul>
<li><p><code>try</code> wraps code that might fail</p>
</li>
<li><p><code>catch</code> handles the failure</p>
</li>
<li><p><code>finally</code> runs cleanup that must happen either way</p>
</li>
<li><p><code>throw</code> raises errors with enough information to diagnose them</p>
</li>
<li><p>Custom error classes make errors specific and catchable by type</p>
</li>
</ul>
<p>The mindset matters as much as the syntax. Ask what can go wrong at each step. Provide a sensible fallback or a clear error message. Log enough context to debug a problem you cannot reproduce. Re-throw errors you cannot handle.</p>
<p>Code that handles errors deliberately is code that tells you the truth when something breaks — which is always better than code that silently does the wrong thing or crashes without explanation.</p>
]]></content:encoded></item><item><title><![CDATA[Spread and Rest Operators in JavaScript: Expanding and Collecting Values]]></title><description><![CDATA[Two of the most useful features introduced in ES6 share identical syntax: three dots (...). One expands values out. The other collects values in. Understanding which is which — and where each one appl]]></description><link>https://blogs.arnabsamanta.in/spread-and-rest-operators-in-javascript-expanding-and-collecting-values</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/spread-and-rest-operators-in-javascript-expanding-and-collecting-values</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 04:41:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/cb051ec8-b024-42bc-9d15-cc36edf66750.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Two of the most useful features introduced in ES6 share identical syntax: three dots (<code>...</code>). One expands values out. The other collects values in. Understanding which is which — and where each one applies — makes a large set of everyday JavaScript patterns feel natural.</p>
<p>This article covers both operators completely: what they do, how they differ, and where they show up in real code.</p>
<hr />
<h2>The Core Idea: Expanding vs Collecting</h2>
<p>The three-dot syntax does one of two opposite things depending on context:</p>
<ul>
<li><p><strong>Spread</strong> takes something iterable and expands it into individual elements. Many becomes many.</p>
</li>
<li><p><strong>Rest</strong> takes individual elements and collects them into a single array. Many becomes one.</p>
</li>
</ul>
<pre><code class="language-plaintext">Spread:  [1, 2, 3]  →  1, 2, 3   (array expands into separate values)
Rest:    1, 2, 3    →  [1, 2, 3]  (separate values collected into array)
</code></pre>
<p>The context tells you which one you are looking at. Inside a function call or an array/object literal, <code>...</code> is spread. In a function parameter list or a destructuring pattern, <code>...</code> is rest.</p>
<hr />
<h2>The Spread Operator</h2>
<p>The spread operator expands an iterable — an array, string, or any object with a <code>Symbol.iterator</code> — into individual elements where separate values are expected.</p>
<h3>Spreading into an array</h3>
<pre><code class="language-js">const a = [1, 2, 3];
const b = [4, 5, 6];

const combined = [...a, ...b];
console.log(combined); // [1, 2, 3, 4, 5, 6]
</code></pre>
<p>Without spread, <code>[a, b]</code> would give you an array of two arrays: <code>[[1, 2, 3], [4, 5, 6]]</code>. Spread unpacks each array so its elements become direct members of the new array.</p>
<p>You can mix spread elements with literal values in any order:</p>
<pre><code class="language-js">const nums = [2, 3, 4];

const withBoundaries = [1, ...nums, 5];
console.log(withBoundaries); // [1, 2, 3, 4, 5]
</code></pre>
<h3>Spreading into a function call</h3>
<p>A function call expects individual arguments. Spread lets you pass an array where a list of arguments is expected:</p>
<pre><code class="language-js">function add(x, y, z) {
  return x + y + z;
}

const values = [10, 20, 30];
add(...values); // 60
</code></pre>
<p>Before spread, this required <code>Function.prototype.apply</code>:</p>
<pre><code class="language-js">add.apply(null, values); // 60 — the old way
</code></pre>
<p>Spread is cleaner and more readable. It also works anywhere in the argument list:</p>
<pre><code class="language-js">Math.max(...[3, 1, 7, 2]); // 7
Math.min(0, ...[3, 1, 7]); // 0
</code></pre>
<h3>Spreading a string</h3>
<p>Strings are iterable, so spread works on them too — each character becomes a separate element:</p>
<pre><code class="language-js">const chars = [..."hello"];
console.log(chars); // ["h", "e", "l", "l", "o"]
</code></pre>
<p>This is a clean way to split a string into characters, and unlike <code>split("")</code>, it handles Unicode code points correctly.</p>
<hr />
<h2>Spread with Objects</h2>
<p>The spread operator also works with objects (using the object spread syntax, not the iterable protocol). It copies enumerable own properties from one object into another.</p>
<h3>Copying an object</h3>
<pre><code class="language-js">const original = { name: "Priya", age: 28 };
const copy = { ...original };

copy.age = 30;

console.log(original.age); // 28 — not affected
console.log(copy.age);     // 30
</code></pre>
<p>This creates a shallow copy. Primitive values (<code>name</code>, <code>age</code>) are copied by value. Nested objects would still be shared references.</p>
<h3>Merging objects</h3>
<pre><code class="language-js">const defaults = { theme: "light", language: "en", fontSize: 14 };
const userPrefs = { theme: "dark", fontSize: 16 };

const settings = { ...defaults, ...userPrefs };
console.log(settings);
// { theme: "dark", language: "en", fontSize: 16 }
</code></pre>
<p>Properties that appear later in the spread override earlier ones. <code>userPrefs</code> spreads after <code>defaults</code>, so <code>theme</code> and <code>fontSize</code> from <code>userPrefs</code> win. <code>language</code> comes only from <code>defaults</code>, so it remains.</p>
<p>This makes object spread the clean way to apply overrides — default configuration merged with user-specific overrides.</p>
<h3>Adding or overriding specific properties</h3>
<pre><code class="language-js">const user = { name: "Rahul", role: "user", active: true };

const adminUser = { ...user, role: "admin" };
console.log(adminUser);
// { name: "Rahul", role: "admin", active: true }
</code></pre>
<p>Spread <code>user</code> first, then specify the override. Property order in the literal determines which value wins — later properties override earlier ones.</p>
<hr />
<h2>The Rest Operator</h2>
<p>Rest does the opposite of spread. It collects multiple values into a single array. It appears in two places: function parameter lists and destructuring patterns.</p>
<h3>Rest parameters in functions</h3>
<p>Rest parameters let a function accept any number of arguments and collect the extras into an array:</p>
<pre><code class="language-js">function sum(...numbers) {
  return numbers.reduce((total, n) =&gt; total + n, 0);
}

sum(1, 2, 3);       // 6
sum(10, 20);        // 30
sum(1, 2, 3, 4, 5); // 15
</code></pre>
<p><code>numbers</code> is always a real array — you can call <code>reduce</code>, <code>map</code>, <code>filter</code>, and any other array method on it directly.</p>
<p>Before rest parameters, <code>arguments</code> was the tool for this:</p>
<pre><code class="language-js">function sum() {
  return Array.from(arguments).reduce((total, n) =&gt; total + n, 0);
}
</code></pre>
<p><code>arguments</code> has two problems: it is not a real array (no array methods without conversion), and it does not work inside arrow functions. Rest parameters solve both.</p>
<h3>Rest must be last</h3>
<p>The rest parameter collects "everything that remains," so it can only appear at the end of the parameter list:</p>
<pre><code class="language-js">function log(level, timestamp, ...messages) {
  console.log(`[\({level}] \){timestamp}:`, messages.join(" | "));
}

log("INFO", "10:30", "Server started", "Port 3000", "Ready");
// [INFO] 10:30: Server started | Port 3000 | Ready
</code></pre>
<p><code>level</code> and <code>timestamp</code> capture the first two arguments. <code>messages</code> collects everything after. This pattern — specific named parameters first, then rest — is common for utility and logging functions.</p>
<h3>Rest in array destructuring</h3>
<p>Rest in a destructuring pattern collects the remaining elements after specific ones have been extracted:</p>
<pre><code class="language-js">const [first, second, ...remaining] = [10, 20, 30, 40, 50];

console.log(first);     // 10
console.log(second);    // 20
console.log(remaining); // [30, 40, 50]
</code></pre>
<p><code>remaining</code> is always an array — even if there is only one element left, or none at all:</p>
<pre><code class="language-js">const [head, ...tail] = [1];
console.log(head); // 1
console.log(tail); // []
</code></pre>
<h3>Rest in object destructuring</h3>
<p>Rest in object destructuring collects the properties that were not explicitly extracted:</p>
<pre><code class="language-js">const user = { name: "Priya", age: 28, role: "admin", active: true };

const { name, role, ...rest } = user;

console.log(name); // "Priya"
console.log(role); // "admin"
console.log(rest); // { age: 28, active: true }
</code></pre>
<p><code>rest</code> is a new object containing only the properties that were not named explicitly. This is how you "pick" properties from an object without mutating it.</p>
<hr />
<h2>Spread vs Rest: Side by Side</h2>
<p>Same syntax, opposite directions:</p>
<table>
<thead>
<tr>
<th></th>
<th>Spread</th>
<th>Rest</th>
</tr>
</thead>
<tbody><tr>
<td>Direction</td>
<td>Expands one into many</td>
<td>Collects many into one</td>
</tr>
<tr>
<td>Where it appears</td>
<td>Array literals, object literals, function calls</td>
<td>Function parameters, destructuring patterns</td>
</tr>
<tr>
<td>Input</td>
<td>Iterable or object</td>
<td>Multiple values or remaining elements</td>
</tr>
<tr>
<td>Output</td>
<td>Individual elements</td>
<td>A single array or object</td>
</tr>
</tbody></table>
<pre><code class="language-js">// Spread — one array expands into individual arguments
Math.max(...[3, 1, 4, 1, 5]); // 5

// Rest — individual arguments collected into one array
function max(...nums) {
  return Math.max(...nums); // spread again inside
}
max(3, 1, 4, 1, 5); // 5
</code></pre>
<p>Notice the symmetry: <code>max</code> uses rest to collect the arguments into <code>nums</code>, then uses spread to pass them to <code>Math.max</code>. Collect, then expand.</p>
<hr />
<h2>Practical Use Cases</h2>
<h3>Cloning an array</h3>
<pre><code class="language-js">const original = [1, 2, 3];
const clone = [...original];

clone.push(4);

console.log(original); // [1, 2, 3] — unaffected
console.log(clone);    // [1, 2, 3, 4]
</code></pre>
<p>This replaces <code>original.slice()</code> with something more readable. The clone is a new array — mutations do not propagate back to <code>original</code>.</p>
<h3>Merging arrays</h3>
<pre><code class="language-js">const frontend = ["React", "CSS", "TypeScript"];
const backend  = ["Node.js", "PostgreSQL", "Redis"];

const fullStack = [...frontend, ...backend];
// ["React", "CSS", "TypeScript", "Node.js", "PostgreSQL", "Redis"]
</code></pre>
<p>As many arrays as you like, in any order, with optional literal values between them.</p>
<h3>Converting a Set to an array</h3>
<pre><code class="language-js">const unique = new Set([1, 2, 2, 3, 3, 4]);
const arr = [...unique];

console.log(arr); // [1, 2, 3, 4]
</code></pre>
<p><code>Set</code> is iterable, so spread works. This is the cleanest way to deduplicate an array:</p>
<pre><code class="language-js">const deduped = [...new Set([1, 2, 2, 3, 3, 4])];
</code></pre>
<h3>Converting a NodeList to an array</h3>
<p>When you query the DOM, <code>querySelectorAll</code> returns a <code>NodeList</code>, not a real array. Spread converts it:</p>
<pre><code class="language-js">const elements = [...document.querySelectorAll(".card")];
elements.filter(el =&gt; el.classList.contains("active")); // now you can use array methods
</code></pre>
<h3>Building modified copies of objects</h3>
<p>In React and other state-management patterns, you need to update objects without mutating the original. Spread makes this clean:</p>
<pre><code class="language-js">const user = { name: "Priya", age: 28, city: "Mumbai" };

// Update one field
const older = { ...user, age: 29 };

// Add a new field
const withEmail = { ...user, email: "priya@example.com" };

// Remove a field (using rest destructuring)
const { city, ...withoutCity } = user;
</code></pre>
<p>All three patterns produce new objects without touching the original. This is the pattern used constantly in Redux reducers and React state updates.</p>
<h3>Passing dynamic arguments</h3>
<p>When you have arguments that may vary in count, spread lets you handle them uniformly:</p>
<pre><code class="language-js">function formatMessage(template, ...values) {
  return template.replace(/\{(\d+)\}/g, (_, i) =&gt; values[i] ?? "");
}

formatMessage("Hello, {0}! You have {1} messages.", "Priya", 5);
// "Hello, Priya! You have 5 messages."
</code></pre>
<p>Rest collects the substitution values, and the function handles any number of them.</p>
<h3>Merging default configuration with overrides</h3>
<p>This is one of the most common real-world uses of object spread:</p>
<pre><code class="language-js">function createRequest(options) {
  const defaults = {
    method: "GET",
    headers: { "Content-Type": "application/json" },
    timeout: 5000,
    retry: true
  };

  return { ...defaults, ...options };
}

createRequest({ method: "POST", timeout: 10000 });
// { method: "POST", headers: {...}, timeout: 10000, retry: true }
</code></pre>
<p><code>defaults</code> provides a baseline. <code>options</code> overrides only what the caller specifies. Everything else remains at the default value.</p>
<h3>Collecting remaining items after destructuring</h3>
<pre><code class="language-js">function processOrder({ id, status, ...details }) {
  console.log(`Order \({id} is \){status}`);
  console.log("Additional details:", details);
}

processOrder({
  id: "ORD-001",
  status: "shipped",
  customer: "Priya",
  address: "Mumbai",
  total: 1499
});
// Order ORD-001 is shipped
// Additional details: { customer: "Priya", address: "Mumbai", total: 1499 }
</code></pre>
<p>The function extracts what it needs and passes the rest along without having to enumerate every property.</p>
<hr />
<h2>Things to Watch Out For</h2>
<h3>Spread creates shallow copies</h3>
<p>Spread copies references for nested objects, not the objects themselves:</p>
<pre><code class="language-js">const original = { name: "Priya", address: { city: "Mumbai" } };
const copy = { ...original };

copy.address.city = "Delhi"; // mutates the nested object

console.log(original.address.city); // "Delhi" — original affected
</code></pre>
<p><code>copy.address</code> and <code>original.address</code> point to the same object. If you need a deep copy, you need a different approach — <code>structuredClone()</code>, a recursion, or a library.</p>
<h3>Rest only works at the end</h3>
<p>In both function parameters and destructuring, rest must be the last element. Placing it elsewhere is a syntax error:</p>
<pre><code class="language-js">function bad(...args, last) { } // SyntaxError

const [...rest, last] = [1, 2, 3]; // SyntaxError
</code></pre>
<h3>Spread does not deep-merge objects</h3>
<p>When two spread objects share a nested property, the second replaces the first entirely — it does not merge them:</p>
<pre><code class="language-js">const a = { config: { debug: true, verbose: false } };
const b = { config: { verbose: true } };

const merged = { ...a, ...b };
console.log(merged.config); // { verbose: true } — debug is gone
</code></pre>
<p><code>b.config</code> overwrites <code>a.config</code> completely. If you need recursive merging, use a utility like <code>lodash.merge</code> or write a deep merge function.</p>
<hr />
<h2>Quick Reference</h2>
<pre><code class="language-js">// Spread into array
[...arr]
[...arr1, ...arr2]
[value, ...arr, value]

// Spread into function call
fn(...arr)
Math.max(...numbers)

// Spread into object
{ ...obj }
{ ...defaults, ...overrides }
{ ...obj, key: newValue }

// Rest parameters
function fn(...args) {}
function fn(first, second, ...rest) {}

// Rest in array destructuring
const [a, b, ...rest] = arr;
const [head, ...tail] = arr;

// Rest in object destructuring
const { key1, key2, ...rest } = obj;
</code></pre>
<hr />
<h2>Wrapping Up</h2>
<p>The <code>...</code> syntax is one of the most versatile additions to modern JavaScript. The key is reading it directionally: spread pushes values out of a container; rest pulls values into one.</p>
<p>Once you see it that way, the patterns follow naturally. Cloning an array, merging objects, collecting variadic function arguments, skipping specific destructured values — all of these use the same two ideas applied in different positions.</p>
<p>The practical benefit is code that is shorter, clearer, and easier to reason about. A spread merge communicates intent directly. A rest parameter eliminates the need to document that a function takes a variable number of arguments. The three dots do a lot of heavy lifting.</p>
]]></content:encoded></item><item><title><![CDATA[String Methods and Polyfills in JavaScript: Logic Behind the Built-Ins]]></title><description><![CDATA[JavaScript ships with a rich set of string methods. Most developers use them every day without thinking much about what is happening underneath. That works fine — until an interviewer asks you to impl]]></description><link>https://blogs.arnabsamanta.in/string-methods-and-polyfills-in-javascript-logic-behind-the-built-ins</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/string-methods-and-polyfills-in-javascript-logic-behind-the-built-ins</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Mon, 30 Mar 2026 04:36:26 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/35b39e38-f075-4b53-b49e-29e9862462ef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>JavaScript ships with a rich set of string methods. Most developers use them every day without thinking much about what is happening underneath. That works fine — until an interviewer asks you to implement one from scratch, or until you need to support an environment where a method does not exist yet.</p>
<p>This article covers both situations. You will understand how common string methods work conceptually, implement polyfills for them, and work through the string problems that show up most often in technical interviews.</p>
<hr />
<h2>What String Methods Are</h2>
<p>String methods are functions built into JavaScript's <code>String.prototype</code> that let you manipulate, search, transform, and inspect strings. Because every string in JavaScript inherits from <code>String.prototype</code>, any method on that prototype is available on every string.</p>
<pre><code class="language-js">const str = "hello world";

str.toUpperCase();   // "HELLO WORLD"
str.includes("world"); // true
str.split(" ");      // ["hello", "world"]
str.trim();          // "hello world" (no change here — no whitespace)
</code></pre>
<p>These methods do not modify the original string. Strings in JavaScript are immutable — every operation returns a new string. That is an important detail when you implement your own versions.</p>
<hr />
<h2>Why Developers Write Polyfills</h2>
<p>A polyfill is a piece of code that implements a feature that the current environment does not natively support — typically an older browser or an older version of Node.js.</p>
<p>The idea is simple: check whether the method already exists. If it does not, add it.</p>
<pre><code class="language-js">if (!String.prototype.includes) {
  String.prototype.includes = function(search, start) {
    // your implementation here
  };
}
</code></pre>
<p>There are three reasons to understand polyfills even if you never have to ship one:</p>
<p><strong>Legacy environments still exist.</strong> Enterprise applications and older mobile browsers sometimes cannot be updated. When a product needs to support IE11, or an embedded system running an old JavaScript engine, polyfills fill the gap between what the language offers now and what the environment supports.</p>
<p><strong>Interviews test them constantly.</strong> "Implement <code>Array.prototype.map</code> from scratch" is a standard interview question. The same pattern applies to string methods: "Write your own <code>includes</code>," "Implement <code>startsWith</code>," "Build a <code>trim</code> function." These questions test whether you understand the contract of the method, not just its name.</p>
<p><strong>They make the built-in behaviour concrete.</strong> When you try to implement <code>repeat("ab", 3)</code> yourself, you immediately think about edge cases: what if count is 0? What if it is negative? What if the string is empty? Understanding the edge cases is understanding the method.</p>
<hr />
<h2>Implementing String Utilities</h2>
<p>For each utility, the approach is the same: state what the method does in plain English, then translate that description directly into code. The built-in implementation is optimised — yours just needs to be correct.</p>
<hr />
<h3><code>includes</code> — does the string contain this substring?</h3>
<p><strong>What it does:</strong> Returns <code>true</code> if the search string appears anywhere in the source string, <code>false</code> otherwise. Optionally accepts a starting position.</p>
<pre><code class="language-js">"hello world".includes("world"); // true
"hello world".includes("xyz");   // false
"hello world".includes("o", 7);  // false — 'o' before position 7
</code></pre>
<p><strong>Conceptual logic:</strong> Walk through the string starting from <code>start</code>. At each position, check whether the characters from that position match the search string, character by character. If you find a complete match, return <code>true</code>. If you exhaust the string, return <code>false</code>.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="language-js">String.prototype.myIncludes = function(search, start = 0) {
  const str = String(this);

  if (search.length === 0) return true;
  if (start &lt; 0) start = 0;
  if (start + search.length &gt; str.length) return false;

  for (let i = start; i &lt;= str.length - search.length; i++) {
    let match = true;
    for (let j = 0; j &lt; search.length; j++) {
      if (str[i + j] !== search[j]) {
        match = false;
        break;
      }
    }
    if (match) return true;
  }

  return false;
};

"hello world".myIncludes("world"); // true
"hello world".myIncludes("xyz");   // false
</code></pre>
<p><strong>What this reveals:</strong> The built-in <code>includes</code> uses a substring search algorithm. The naive approach above runs in O(n × m) time — for each position in the string, it compares up to m characters. More advanced algorithms like Boyer-Moore or KMP do better, but for an interview, the naive version demonstrates the concept correctly.</p>
<hr />
<h3><code>startsWith</code> — does the string begin with this prefix?</h3>
<p><strong>What it does:</strong> Returns <code>true</code> if the string starts with the given prefix, starting from an optional position.</p>
<pre><code class="language-js">"hello world".startsWith("hello"); // true
"hello world".startsWith("world"); // false
"hello world".startsWith("world", 6); // true
</code></pre>
<p><strong>Conceptual logic:</strong> Starting at the given position, compare each character of the prefix against the corresponding character in the source string. If all characters match, the string starts with the prefix.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="language-js">String.prototype.myStartsWith = function(prefix, position = 0) {
  const str = String(this);

  if (position &lt; 0) position = 0;
  if (position + prefix.length &gt; str.length) return false;

  for (let i = 0; i &lt; prefix.length; i++) {
    if (str[position + i] !== prefix[i]) return false;
  }

  return true;
};

"hello world".myStartsWith("hello"); // true
"hello world".myStartsWith("world", 6); // true
</code></pre>
<p><strong>Edge cases to handle:</strong> An empty prefix always returns <code>true</code> (every string starts with nothing). A position beyond the string's length returns <code>false</code>. A negative position is treated as <code>0</code>.</p>
<hr />
<h3><code>endsWith</code> — does the string end with this suffix?</h3>
<p><strong>What it does:</strong> Returns <code>true</code> if the string ends with the given suffix. Optionally accepts an end position to treat as the effective end of the string.</p>
<pre><code class="language-js">"hello world".endsWith("world"); // true
"hello world".endsWith("hello"); // false
"hello world".endsWith("hello", 5); // true — treat only "hello" as the string
</code></pre>
<p><strong>Conceptual logic:</strong> Calculate the effective end of the string. From that point, count backward by the length of the suffix and compare characters.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="language-js">String.prototype.myEndsWith = function(suffix, endPos) {
  const str = String(this);
  const end = endPos === undefined ? str.length : Math.min(endPos, str.length);

  if (suffix.length === 0) return true;
  if (suffix.length &gt; end) return false;

  const start = end - suffix.length;

  for (let i = 0; i &lt; suffix.length; i++) {
    if (str[start + i] !== suffix[i]) return false;
  }

  return true;
};

"hello world".myEndsWith("world"); // true
"hello world".myEndsWith("hello", 5); // true
</code></pre>
<hr />
<h3><code>repeat</code> — repeat the string n times</h3>
<p><strong>What it does:</strong> Returns a new string consisting of the original string concatenated with itself <code>count</code> times.</p>
<pre><code class="language-js">"ab".repeat(3);  // "ababab"
"ab".repeat(0);  // ""
"ab".repeat(1);  // "ab"
</code></pre>
<p><strong>Conceptual logic:</strong> Loop <code>count</code> times, appending the string to a result on each iteration. Return the result.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="language-js">String.prototype.myRepeat = function(count) {
  const str = String(this);

  if (count &lt; 0) throw new RangeError("repeat count must be non-negative");
  if (!isFinite(count)) throw new RangeError("repeat count must be finite");

  count = Math.floor(count);
  let result = "";

  for (let i = 0; i &lt; count; i++) {
    result += str;
  }

  return result;
};

"ab".myRepeat(3); // "ababab"
"ab".myRepeat(0); // ""
</code></pre>
<p><strong>A faster approach:</strong> For large counts, you can use a halving technique — double the string and the count, building the result in O(log n) steps instead of O(n). The interview question often asks whether you can optimise beyond the naive loop.</p>
<pre><code class="language-js">function repeatFast(str, count) {
  if (count === 0) return "";
  let result = "";
  let base = str;

  while (count &gt; 0) {
    if (count % 2 === 1) result += base;
    base += base;
    count = Math.floor(count / 2);
  }

  return result;
}

repeatFast("ab", 5); // "ababababab"
</code></pre>
<hr />
<h3><code>trim</code> — remove leading and trailing whitespace</h3>
<p><strong>What it does:</strong> Returns a new string with whitespace removed from both ends. <code>trimStart</code> and <code>trimEnd</code> are one-sided versions.</p>
<pre><code class="language-js">"  hello  ".trim();      // "hello"
"  hello  ".trimStart(); // "hello  "
"  hello  ".trimEnd();   // "  hello"
</code></pre>
<p><strong>Conceptual logic:</strong> Walk inward from the left until you hit a non-whitespace character. Walk inward from the right until you hit a non-whitespace character. Return the slice between those two positions.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="language-js">String.prototype.myTrim = function() {
  const str = String(this);
  const whitespace = " \t\n\r\f\v";

  let left = 0;
  let right = str.length - 1;

  while (left &lt;= right &amp;&amp; whitespace.includes(str[left])) {
    left++;
  }

  while (right &gt;= left &amp;&amp; whitespace.includes(str[right])) {
    right--;
  }

  return str.slice(left, right + 1);
};

"  hello  ".myTrim(); // "hello"
"\t  hello\n".myTrim(); // "hello"
</code></pre>
<p><strong>What counts as whitespace?</strong> The spec includes space, tab (<code>\t</code>), newline (<code>\n</code>), carriage return (<code>\r</code>), form feed (<code>\f</code>), and vertical tab (<code>\v</code>). A simple regex also works: <code>/^\s+|\s+$/g</code>.</p>
<hr />
<h3><code>padStart</code> and <code>padEnd</code> — pad to a target length</h3>
<p><strong>What they do:</strong> If the string is shorter than the target length, add padding characters to the start or end until it reaches that length.</p>
<pre><code class="language-js">"5".padStart(3, "0"); // "005"
"hi".padEnd(5, ".");  // "hi..."
"hello".padStart(3);  // "hello" — already long enough
</code></pre>
<p><strong>Conceptual logic:</strong> Calculate how much padding is needed. Repeat the pad string enough times to fill that space (it might need to be truncated if it does not divide evenly). Concatenate it with the original string.</p>
<p><strong>Implementation:</strong></p>
<pre><code class="language-js">String.prototype.myPadStart = function(targetLength, padString = " ") {
  const str = String(this);

  if (str.length &gt;= targetLength) return str;
  if (padString.length === 0) return str;

  const padNeeded = targetLength - str.length;
  const repeated = padString.repeat(Math.ceil(padNeeded / padString.length));
  return repeated.slice(0, padNeeded) + str;
};

"5".myPadStart(3, "0"); // "005"
"5".myPadStart(5, "ab"); // "abab5"
</code></pre>
<p>The <code>padEnd</code> version is symmetric — concatenate the padding after the string instead of before.</p>
<hr />
<h2>Common Interview String Problems</h2>
<p>These problems appear frequently in technical screens. Each one tests a specific kind of string reasoning.</p>
<hr />
<h3>Reverse a string</h3>
<p>The simplest version uses built-in methods:</p>
<pre><code class="language-js">function reverse(str) {
  return str.split("").reverse().join("");
}
</code></pre>
<p>Interviewers often ask for the manual version:</p>
<pre><code class="language-js">function reverse(str) {
  let result = "";
  for (let i = str.length - 1; i &gt;= 0; i--) {
    result += str[i];
  }
  return result;
}

reverse("hello"); // "olleh"
</code></pre>
<p>The follow-up is almost always: "What about Unicode characters?" Emoji and characters from some scripts are stored as surrogate pairs — two code units that represent one character. The <code>split("")</code> approach splits surrogate pairs, corrupting them. The correct approach uses the spread operator, which handles Unicode code points:</p>
<pre><code class="language-js">function reverseSafe(str) {
  return [...str].reverse().join("");
}

reverseSafe("hello 😊"); // "😊 olleh" — emoji intact
</code></pre>
<hr />
<h3>Check if a string is a palindrome</h3>
<p>A palindrome reads the same forwards and backwards: "racecar", "level", "madam".</p>
<pre><code class="language-js">function isPalindrome(str) {
  const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, "");
  const reversed = [...cleaned].reverse().join("");
  return cleaned === reversed;
}

isPalindrome("racecar");      // true
isPalindrome("A man a plan a canal Panama"); // true
isPalindrome("hello");        // false
</code></pre>
<p>The two-pointer approach avoids creating the reversed string:</p>
<pre><code class="language-js">function isPalindrome(str) {
  const cleaned = str.toLowerCase().replace(/[^a-z0-9]/g, "");
  let left = 0;
  let right = cleaned.length - 1;

  while (left &lt; right) {
    if (cleaned[left] !== cleaned[right]) return false;
    left++;
    right--;
  }

  return true;
}
</code></pre>
<p>Start from both ends and walk inward. If any pair of characters does not match, it is not a palindrome. This runs in O(n) time and O(1) extra space (besides the cleaned string).</p>
<hr />
<h3>Count character occurrences</h3>
<p>Build a frequency map — a simple object where keys are characters and values are counts:</p>
<pre><code class="language-js">function charCount(str) {
  const counts = {};
  for (const char of str) {
    counts[char] = (counts[char] || 0) + 1;
  }
  return counts;
}

charCount("hello");
// { h: 1, e: 1, l: 2, o: 1 }
</code></pre>
<p>This pattern is the foundation for anagram checking, finding the most frequent character, and a dozen other string problems.</p>
<hr />
<h3>Check if two strings are anagrams</h3>
<p>Two strings are anagrams if they contain exactly the same characters in the same quantities.</p>
<pre><code class="language-js">function areAnagrams(str1, str2) {
  if (str1.length !== str2.length) return false;

  const counts = {};

  for (const char of str1) {
    counts[char] = (counts[char] || 0) + 1;
  }

  for (const char of str2) {
    if (!counts[char]) return false;
    counts[char]--;
  }

  return true;
}

areAnagrams("listen", "silent"); // true
areAnagrams("hello", "world");   // false
</code></pre>
<p>Count characters in the first string. Then walk through the second string, decrementing each count. If a character appears in the second string but not the first (or appears too many times), return <code>false</code>.</p>
<p>A simpler but less efficient approach: sort both strings and compare them.</p>
<pre><code class="language-js">function areAnagrams(str1, str2) {
  const sort = s =&gt; s.split("").sort().join("");
  return sort(str1) === sort(str2);
}
</code></pre>
<p>Sorting is O(n log n). The frequency map approach is O(n).</p>
<hr />
<h3>Find the first non-repeating character</h3>
<pre><code class="language-js">function firstUnique(str) {
  const counts = {};

  for (const char of str) {
    counts[char] = (counts[char] || 0) + 1;
  }

  for (let i = 0; i &lt; str.length; i++) {
    if (counts[str[i]] === 1) return str[i];
  }

  return null;
}

firstUnique("aabbcde"); // "c"
firstUnique("aabb");    // null
</code></pre>
<p>Two passes: the first builds the frequency map, the second walks the string in order and returns the first character with a count of <code>1</code>. Order matters here — you need to preserve the original sequence.</p>
<hr />
<h3>Truncate a string to a word boundary</h3>
<p>A real-world utility: shorten a string to fit a character limit, but do not cut in the middle of a word.</p>
<pre><code class="language-js">function truncate(str, maxLength) {
  if (str.length &lt;= maxLength) return str;

  const truncated = str.slice(0, maxLength);
  const lastSpace = truncated.lastIndexOf(" ");

  if (lastSpace === -1) return truncated;
  return truncated.slice(0, lastSpace) + "...";
}

truncate("The quick brown fox jumps over the lazy dog", 20);
// "The quick brown..."
</code></pre>
<p><code>lastIndexOf(" ")</code> finds the last space within the truncated region. Slicing at that position avoids cutting through a word.</p>
<hr />
<h3>Implement <code>String.prototype.split</code> for a single character delimiter</h3>
<p>This is less common as an interview question, but it illustrates the concept behind all parsing:</p>
<pre><code class="language-js">function mySplit(str, delimiter) {
  if (delimiter === "") return [...str];

  const result = [];
  let current = "";

  for (const char of str) {
    if (char === delimiter) {
      result.push(current);
      current = "";
    } else {
      current += char;
    }
  }

  result.push(current);
  return result;
}

mySplit("a,b,c,d", ","); // ["a", "b", "c", "d"]
mySplit("hello", "l");   // ["he", "", "o"]
</code></pre>
<p>Walk through the string one character at a time. When you hit the delimiter, push the accumulated characters as a new element and reset. When you finish, push whatever remains. Note that consecutive delimiters produce empty strings — that is the correct behaviour, matching the native <code>split</code>.</p>
<hr />
<h2>Understanding Built-in Behaviour</h2>
<p>The deeper reason to implement these utilities yourself is not to be able to ship polyfills — it is to understand what the methods actually promise.</p>
<p>When you use <code>" hello ".trim()</code>, you might assume it handles all whitespace. But have you thought about vertical tab? Form feed? Non-breaking space (<code>\u00A0</code>)? The native <code>trim</code> handles all of these because the spec defines whitespace precisely. A naive implementation using just <code>" "</code> would miss them.</p>
<p>When you use <code>"ab".repeat(Infinity)</code>, you get a <code>RangeError</code>. That edge case is in the spec. If your polyfill does not throw there, it behaves differently from the native method — and code that depends on that error will fail silently.</p>
<p>These are the kinds of details that separate a correct polyfill from a broken one, and they are also what interviewers probe. "What if the input is empty?" "What if count is 0?" "What if the delimiter appears at the start?" Every time you write a utility from scratch and think through the edge cases, you build a more accurate mental model of the built-in.</p>
<p>The goal is not to memorise implementations. It is to reach the point where you can reconstruct them from first principles, because you genuinely understand what they are supposed to do.</p>
<hr />
<h2>Wrapping Up</h2>
<p>String methods are not black boxes. They are algorithms — each one translatable into a loop, a comparison, a character-by-character walk through the input. Writing polyfills forces you to make that translation explicit.</p>
<p>The interview questions in this article are not obscure puzzles. They are the same operations that string methods perform, just without the method available. Reversing a string is what <code>split("").reverse().join("")</code> does internally. Checking for a substring is what <code>includes</code> does. Building a frequency map is what powers most character-counting operations.</p>
<p>Understand the logic behind the built-ins, and both the interviews and the occasional need for a real polyfill become straightforward.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding this in JavaScript: Who Is Calling the Function?]]></title><description><![CDATA[this is one of those JavaScript concepts that trips up developers at every level — beginners who cannot get it to work at all, and experienced developers who occasionally get burned by it in unexpecte]]></description><link>https://blogs.arnabsamanta.in/understanding-this-in-javascript-who-is-calling-the-function</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/understanding-this-in-javascript-who-is-calling-the-function</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Sat, 28 Mar 2026 15:40:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/cbfa929a-d2a7-43d3-a125-0a8a43748a0a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><code>this</code> is one of those JavaScript concepts that trips up developers at every level — beginners who cannot get it to work at all, and experienced developers who occasionally get burned by it in unexpected situations.</p>
<p>The reason it confuses people is that most languages have a simpler version of the concept. In Java or Python, <code>this</code> or <code>self</code> is determined by the class the method belongs to. In JavaScript, it is determined by <em>how the function is called</em>, not where it is defined. The same function can have a completely different <code>this</code> depending on who calls it.</p>
<p>That one idea — <code>this</code> is the caller — explains almost every behaviour you will ever encounter.</p>
<hr />
<h2>What <code>this</code> Represents</h2>
<p><code>this</code> is a keyword that refers to the context in which the current function is executing. More specifically, it refers to the object that is the subject of the current call.</p>
<p>Think of a function as a verb, and <code>this</code> as the subject of the sentence. When you say "Priya greets," Priya is doing the greeting. When you say "Rahul greets," Rahul is doing the same action. The verb is the same; the subject changes.</p>
<pre><code class="language-js">function greet() {
  console.log(`Hello, I am ${this.name}`);
}
</code></pre>
<p>The function <code>greet</code> uses <code>this.name</code>. That value depends entirely on what <code>this</code> is when the function runs — which depends entirely on how <code>greet</code> is called.</p>
<p>JavaScript determines <code>this</code> at the moment of the function call, not at the moment of definition. This is the core rule. Everything else follows from it.</p>
<hr />
<h2><code>this</code> in the Global Context</h2>
<p>When you run code outside of any function or object — at the top level of a script — <code>this</code> refers to the global object.</p>
<p>In a browser, the global object is <code>window</code>:</p>
<pre><code class="language-js">console.log(this === window); // true (in browsers)

this.name = "global scope";
console.log(window.name); // "global scope"
</code></pre>
<p>In Node.js, the global object at the top level of a module is an empty object <code>{}</code>, not the true <code>global</code> object. This is a quirk of Node's module system.</p>
<pre><code class="language-js">// In Node.js (at the top of a file)
console.log(this); // {}
</code></pre>
<p>In practice, you rarely use <code>this</code> at the global level intentionally. It matters most when you accidentally end up in the global context without realising it — typically inside a regular function that is not called as a method.</p>
<h3><code>this</code> in a regular function (non-strict mode)</h3>
<p>When a function is called on its own — not as a method of an object — <code>this</code> defaults to the global object in non-strict mode:</p>
<pre><code class="language-js">function showThis() {
  console.log(this);
}

showThis(); // window (in browsers, non-strict mode)
</code></pre>
<p>This is one of the most common sources of bugs. You expect <code>this</code> to be something specific, but it ends up being <code>window</code> because the function was called without a clear caller.</p>
<h3><code>this</code> in strict mode</h3>
<p>In strict mode, a standalone function call gives you <code>undefined</code> for <code>this</code> instead of the global object:</p>
<pre><code class="language-js">"use strict";

function showThis() {
  console.log(this);
}

showThis(); // undefined
</code></pre>
<p>Strict mode is the safer behaviour — <code>undefined</code> makes the mistake obvious immediately. Non-strict mode's silent fallback to <code>window</code> hides the bug and can cause hard-to-trace errors when you accidentally set properties on the global object.</p>
<hr />
<h2><code>this</code> Inside Objects</h2>
<p>When a function is called as a method of an object — using dot notation — <code>this</code> refers to the object before the dot.</p>
<pre><code class="language-js">const user = {
  name: "Priya",
  greet() {
    console.log(`Hello, I am ${this.name}`);
  }
};

user.greet(); // Hello, I am Priya
</code></pre>
<p>Here, <code>user</code> is the object before the dot. When <code>greet</code> is called as <code>user.greet()</code>, JavaScript sets <code>this</code> to <code>user</code> inside the function. So <code>this.name</code> is <code>user.name</code>, which is <code>"Priya"</code>.</p>
<p>This is the most intuitive use of <code>this</code>. The object is clearly the caller — <code>user.greet()</code> reads as "user does greet," and <code>this</code> inside <code>greet</code> is <code>user</code>.</p>
<h3>Multiple objects, same function</h3>
<p>Because <code>this</code> is determined by the call, the same function can produce different results depending on which object calls it:</p>
<pre><code class="language-js">function introduce() {
  console.log(`I am \({this.name}, aged \){this.age}`);
}

const person1 = { name: "Priya", age: 28, introduce };
const person2 = { name: "Rahul", age: 34, introduce };

person1.introduce(); // I am Priya, aged 28
person2.introduce(); // I am Rahul, aged 34
</code></pre>
<p><code>introduce</code> is defined once. It is attached to two objects. When called on <code>person1</code>, <code>this</code> is <code>person1</code>. When called on <code>person2</code>, <code>this</code> is <code>person2</code>. The function is identical — only the caller changes.</p>
<h3>Nested objects</h3>
<p>The rule is always the <em>immediate</em> object before the dot:</p>
<pre><code class="language-js">const company = {
  name: "Acme Corp",
  ceo: {
    name: "Ananya",
    introduce() {
      console.log(`I am ${this.name}`);
    }
  }
};

company.ceo.introduce(); // I am Ananya
</code></pre>
<p>The call is <code>company.ceo.introduce()</code>. The immediate caller is <code>ceo</code>, not <code>company</code>. So <code>this</code> is <code>company.ceo</code>, and <code>this.name</code> is <code>"Ananya"</code>.</p>
<hr />
<h2><code>this</code> Inside Regular Functions</h2>
<p>The behaviour of <code>this</code> inside a regular function depends entirely on how the function is called — not where it is defined. This is the source of most <code>this</code>-related confusion.</p>
<h3>Losing <code>this</code> when assigning a method to a variable</h3>
<pre><code class="language-js">const user = {
  name: "Priya",
  greet() {
    console.log(`Hello, I am ${this.name}`);
  }
};

user.greet(); // Hello, I am Priya — this = user

const fn = user.greet; // store the function in a variable
fn();                   // Hello, I am undefined — this = window (or undefined in strict mode)
</code></pre>
<p><code>fn</code> holds the same function as <code>user.greet</code>. But when you call <code>fn()</code>, there is no object before the dot. There is no clear caller. JavaScript falls back to the global object (or <code>undefined</code> in strict mode). The function lost its <code>this</code> the moment it was detached from <code>user</code>.</p>
<p>This happens constantly with event handlers and callbacks — you pass a method somewhere, it gets called as a plain function, and <code>this</code> is no longer the object you expected.</p>
<pre><code class="language-js">const timer = {
  name: "Countdown",
  start() {
    setTimeout(function() {
      console.log(`${this.name} started`); // this.name is undefined
    }, 1000);
  }
};

timer.start();
</code></pre>
<p><code>start</code> is called on <code>timer</code>, so inside <code>start</code>, <code>this</code> is <code>timer</code>. But the callback passed to <code>setTimeout</code> is called by the browser's timer mechanism — not by <code>timer</code>. It has no caller object, so <code>this</code> is the global object. <code>this.name</code> is not <code>"Countdown"</code>.</p>
<h3>Preserving <code>this</code> with a variable</h3>
<p>One classic solution is to capture <code>this</code> before entering the nested function:</p>
<pre><code class="language-js">const timer = {
  name: "Countdown",
  start() {
    const self = this; // capture this = timer
    setTimeout(function() {
      console.log(`${self.name} started`); // Countdown started
    }, 1000);
  }
};

timer.start();
</code></pre>
<p><code>self</code> is a regular variable that closes over the outer <code>this</code>. The inner function uses <code>self</code> instead of <code>this</code>. This works but feels like a workaround — and it is. Arrow functions solve this more cleanly.</p>
<hr />
<h2>Arrow Functions and <code>this</code></h2>
<p>Arrow functions do not have their own <code>this</code>. Instead, they inherit <code>this</code> from the surrounding lexical scope — the context where the arrow function was <em>written</em>, not where it is called.</p>
<pre><code class="language-js">const timer = {
  name: "Countdown",
  start() {
    setTimeout(() =&gt; {
      console.log(`${this.name} started`); // Countdown started
    }, 1000);
  }
};

timer.start();
</code></pre>
<p>The arrow function <code>() =&gt; { ... }</code> is written inside <code>start</code>, where <code>this</code> is <code>timer</code>. The arrow function captures that <code>this</code> and keeps it regardless of how or when the callback is eventually called. No <code>self</code> variable needed.</p>
<p>This makes arrow functions the natural choice for callbacks inside methods:</p>
<pre><code class="language-js">const user = {
  name: "Priya",
  hobbies: ["reading", "coding", "hiking"],
  listHobbies() {
    this.hobbies.forEach(hobby =&gt; {
      console.log(`\({this.name} likes \){hobby}`);
    });
  }
};

user.listHobbies();
// Priya likes reading
// Priya likes coding
// Priya likes hiking
</code></pre>
<p>The arrow function passed to <code>forEach</code> uses <code>this.name</code> without any trouble, because it inherits <code>this</code> from <code>listHobbies</code>, where <code>this</code> is <code>user</code>.</p>
<h3>When not to use arrow functions as methods</h3>
<p>Arrow functions inherit <code>this</code> from where they are defined — which means if you define an arrow function directly as an object method, <code>this</code> will not be the object:</p>
<pre><code class="language-js">const user = {
  name: "Priya",
  greet: () =&gt; {
    console.log(`Hello, I am ${this.name}`); // this is NOT user
  }
};

user.greet(); // Hello, I am undefined
</code></pre>
<p>The arrow function is defined in the global scope (outside any function), so <code>this</code> in the arrow function is the global object, not <code>user</code>. Arrow functions are for callbacks and nested functions — regular function syntax is for object methods.</p>
<hr />
<h2>How Calling Context Changes <code>this</code></h2>
<p>The calling context is everything. Here are the three main patterns, summarised:</p>
<h3>Pattern 1: Method call — <code>this</code> is the object before the dot</h3>
<pre><code class="language-js">object.method(); // this = object
</code></pre>
<pre><code class="language-js">const car = {
  brand: "Toyota",
  describe() {
    console.log(`This is a ${this.brand}`);
  }
};

car.describe(); // This is a Toyota — this = car
</code></pre>
<h3>Pattern 2: Plain function call — <code>this</code> is global (or <code>undefined</code> in strict mode)</h3>
<pre><code class="language-js">fn(); // this = window / undefined
</code></pre>
<pre><code class="language-js">function describe() {
  console.log(this);
}

describe(); // window (non-strict) or undefined (strict)
</code></pre>
<h3>Pattern 3: Constructor call — <code>this</code> is the new object</h3>
<p>When a function is called with <code>new</code>, <code>this</code> refers to the newly created object:</p>
<pre><code class="language-js">function Car(brand) {
  this.brand = brand; // this = the new object
}

const myCar = new Car("Toyota");
console.log(myCar.brand); // Toyota
</code></pre>
<p>This is how constructor functions work — <code>new</code> creates a fresh object and sets it as <code>this</code> for the duration of the constructor call.</p>
<hr />
<h2>Explicitly Controlling <code>this</code>: <code>call</code>, <code>apply</code>, and <code>bind</code></h2>
<p>JavaScript gives you three tools to set <code>this</code> manually, regardless of how the function would normally be called.</p>
<h3><code>call</code> — invoke now with a specific <code>this</code></h3>
<pre><code class="language-js">function greet(greeting) {
  console.log(`\({greeting}, I am \){this.name}`);
}

const user = { name: "Priya" };

greet.call(user, "Hello"); // Hello, I am Priya
</code></pre>
<p><code>call</code> invokes the function immediately. The first argument becomes <code>this</code>; subsequent arguments are passed to the function.</p>
<h3><code>apply</code> — same as <code>call</code>, but arguments as an array</h3>
<pre><code class="language-js">greet.apply(user, ["Namaste"]); // Namaste, I am Priya
</code></pre>
<p><code>apply</code> is useful when the arguments are already in an array.</p>
<h3><code>bind</code> — create a new function with <code>this</code> fixed</h3>
<pre><code class="language-js">const greetPriya = greet.bind(user);

greetPriya("Hello"); // Hello, I am Priya
greetPriya("Hi");    // Hi, I am Priya
</code></pre>
<p><code>bind</code> does not call the function. It creates a new function with <code>this</code> permanently set to the object you pass. That new function always uses <code>user</code> as <code>this</code>, no matter how or where it is called later.</p>
<p><code>bind</code> is particularly useful for event handlers:</p>
<pre><code class="language-js">const button = {
  label: "Submit",
  handleClick() {
    console.log(`${this.label} was clicked`);
  }
};

document.querySelector("button")
  .addEventListener("click", button.handleClick.bind(button));
</code></pre>
<p>Without <code>bind</code>, the event handler would lose its <code>this</code> when called by the browser. With <code>bind</code>, <code>this</code> is permanently set to <code>button</code>.</p>
<hr />
<h2><code>this</code> Inside Classes</h2>
<p>ES6 classes use <code>this</code> the same way constructor functions do. Inside a class method, <code>this</code> refers to the instance:</p>
<pre><code class="language-js">class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hi, I am \({this.name} and I am \){this.age} years old`);
  }
}

const user1 = new User("Priya", 28);
const user2 = new User("Rahul", 34);

user1.greet(); // Hi, I am Priya and I am 28 years old
user2.greet(); // Hi, I am Rahul and I am 34 years old
</code></pre>
<p>The same calling-context rule applies. <code>user1.greet()</code> sets <code>this</code> to <code>user1</code>. <code>user2.greet()</code> sets <code>this</code> to <code>user2</code>.</p>
<p>Class methods can also lose <code>this</code> when passed as callbacks. The fix is the same: use <code>bind</code> in the constructor, or use an arrow function class field (a more modern syntax):</p>
<pre><code class="language-js">class User {
  constructor(name) {
    this.name = name;
    // Option 1: bind in constructor
    this.greet = this.greet.bind(this);
  }

  greet() {
    console.log(`Hi, I am ${this.name}`);
  }
}

// Option 2: arrow function as a class field (modern syntax)
class User {
  constructor(name) {
    this.name = name;
  }

  greet = () =&gt; {
    console.log(`Hi, I am ${this.name}`);
  };
}
</code></pre>
<p>Arrow function class fields capture <code>this</code> at construction time. They are widely used in React components for exactly this reason.</p>
<hr />
<h2>A Mental Model: The Object Before the Dot</h2>
<p>When you are unsure what <code>this</code> is inside a function, ask one question: <em>what is to the left of the dot at the point of the call?</em></p>
<pre><code class="language-js">user.greet();          // this = user
company.ceo.greet();   // this = company.ceo (the immediate caller)
greet();               // no dot — this = global / undefined
new User("Priya");     // new — this = fresh object
greet.call(user);      // explicit — this = user
</code></pre>
<p>If there is an object before the dot, that is <code>this</code>. If there is no dot, <code>this</code> falls back to the global object or <code>undefined</code>. If <code>new</code> is involved, <code>this</code> is the new object being created. If <code>call</code>, <code>apply</code>, or <code>bind</code> is involved, <code>this</code> is whatever you passed as the first argument.</p>
<p>That covers the vast majority of real-world cases.</p>
<hr />
<h2>Common Mistakes and Their Fixes</h2>
<p><strong>Mistake: Passing a method as a callback and losing</strong> <code>this</code></p>
<pre><code class="language-js">// Problem
setTimeout(user.greet, 1000); // this = window inside greet

// Fix: bind
setTimeout(user.greet.bind(user), 1000);

// Fix: arrow function wrapper
setTimeout(() =&gt; user.greet(), 1000);
</code></pre>
<p><strong>Mistake: Using an arrow function as an object method</strong></p>
<pre><code class="language-js">// Problem
const user = {
  name: "Priya",
  greet: () =&gt; console.log(this.name) // this = global, not user
};

// Fix: use regular function syntax for methods
const user = {
  name: "Priya",
  greet() { console.log(this.name); } // this = user
};
</code></pre>
<p><strong>Mistake: Forgetting</strong> <code>this</code> <strong>inside a nested callback</strong></p>
<pre><code class="language-js">// Problem
const user = {
  name: "Priya",
  loadData() {
    fetchData(function(data) {
      console.log(this.name); // this = window, not user
    });
  }
};

// Fix: arrow function
const user = {
  name: "Priya",
  loadData() {
    fetchData((data) =&gt; {
      console.log(this.name); // this = user — inherited from loadData
    });
  }
};
</code></pre>
<hr />
<h2>Wrapping Up</h2>
<p><code>this</code> in JavaScript is not a fixed property of a function — it is a dynamic value determined at the moment of the call. The rules, once internalised, are consistent:</p>
<ul>
<li><p>Method call on an object: <code>this</code> is that object.</p>
</li>
<li><p>Plain function call: <code>this</code> is global (or <code>undefined</code> in strict mode).</p>
</li>
<li><p>Constructor call with <code>new</code>: <code>this</code> is the newly created object.</p>
</li>
<li><p>Explicit call with <code>call</code>, <code>apply</code>, or <code>bind</code>: <code>this</code> is whatever you specify.</p>
</li>
<li><p>Arrow function: <code>this</code> is inherited from the surrounding lexical scope.</p>
</li>
</ul>
<p>The mental shortcut — look at what is to the left of the dot — gets you the right answer in most cases. For the rest, understanding that <code>this</code> is about calling context, not definition context, fills in the gaps.</p>
<p>Once this clicks, a large class of JavaScript bugs becomes easy to diagnose and fix. You stop being surprised by <code>undefined</code>, and you start having a clear reason for every value <code>this</code> takes.</p>
]]></content:encoded></item><item><title><![CDATA[The new Keyword in JavaScript: Constructors, Prototypes, and How Objects Are Born]]></title><description><![CDATA[Every JavaScript developer uses objects constantly. But not everyone thinks carefully about where objects come from — how they get created, what links them to shared behaviour, and what the new keywor]]></description><link>https://blogs.arnabsamanta.in/the-new-keyword-in-javascript-constructors-prototypes-and-how-objects-are-born</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/the-new-keyword-in-javascript-constructors-prototypes-and-how-objects-are-born</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Sat, 28 Mar 2026 15:00:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/c2f3c6d2-ad30-47f9-8ddb-b6478f2f6acc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every JavaScript developer uses objects constantly. But not everyone thinks carefully about where objects come from — how they get created, what links them to shared behaviour, and what the <code>new</code> keyword is actually doing behind the scenes.</p>
<p>Understanding <code>new</code> is understanding one of the core mechanisms of JavaScript itself. This article walks through it completely: what <code>new</code> does step by step, how constructor functions work, how instances relate to their constructor, and how prototypes are wired up in the process.</p>
<hr />
<h2>Starting Point: Creating Objects Without <code>new</code></h2>
<p>Before looking at <code>new</code>, it helps to see the limitation it solves.</p>
<p>The simplest way to create an object in JavaScript is an object literal:</p>
<pre><code class="language-js">const user = {
  name: "Priya",
  age: 28,
  greet() {
    console.log(`Hi, I'm ${this.name}`);
  }
};

user.greet(); // Hi, I'm Priya
</code></pre>
<p>This works perfectly for one object. But what if you need to create fifty users, all with the same shape — <code>name</code>, <code>age</code>, and a <code>greet</code> method? You could copy and paste the literal fifty times, changing the values each time. That is obviously not a solution.</p>
<p>A factory function helps:</p>
<pre><code class="language-js">function createUser(name, age) {
  return {
    name,
    age,
    greet() {
      console.log(`Hi, I'm ${this.name}`);
    }
  };
}

const user1 = createUser("Priya", 28);
const user2 = createUser("Rahul", 34);
</code></pre>
<p>Better. But there is a problem: every object created by <code>createUser</code> gets its own separate copy of the <code>greet</code> function. Fifty users means fifty identical <code>greet</code> functions in memory. For a method that never changes, this is wasteful. It also means <code>user1.greet !== user2.greet</code> — they are different function objects even though they do the same thing.</p>
<p>The <code>new</code> keyword, combined with constructor functions and prototype linking, solves this. All instances share one copy of shared methods.</p>
<hr />
<h2>Constructor Functions</h2>
<p>A constructor function is an ordinary JavaScript function written with the convention that it will be called with <code>new</code>. By convention, constructor function names start with a capital letter — this is not enforced by the language, but it signals to other developers (and your future self) that this function is meant to be used with <code>new</code>.</p>
<pre><code class="language-js">function User(name, age) {
  this.name = name;
  this.age = age;
}
</code></pre>
<p>Notice there is no <code>return</code> statement. There is no object literal being built up. Just assignments to <code>this</code>. On its own, calling this function without <code>new</code> would either do nothing useful or cause an error — <code>this</code> would not be what you expect.</p>
<p>Called with <code>new</code>, everything changes.</p>
<pre><code class="language-js">const user1 = new User("Priya", 28);
const user2 = new User("Rahul", 34);

console.log(user1.name); // Priya
console.log(user2.age);  // 34
</code></pre>
<p><code>user1</code> and <code>user2</code> are independent objects, each with their own <code>name</code> and <code>age</code> properties. The constructor function served as a template for both.</p>
<hr />
<h2>What <code>new</code> Does: Step by Step</h2>
<p>When you write <code>new User("Priya", 28)</code>, JavaScript performs four distinct steps. None of them are magic — understanding each one removes all the mystery from the keyword.</p>
<h3>Step 1: A new empty object is created</h3>
<p>JavaScript creates a brand new plain object. You can think of it as:</p>
<pre><code class="language-js">const obj = {};
</code></pre>
<p>This object exists in memory, but it has no properties yet and is not yet connected to anything.</p>
<h3>Step 2: The object's prototype is linked</h3>
<p>The new object's internal <code>[[Prototype]]</code> is set to <code>User.prototype</code>. Every function in JavaScript automatically has a <code>prototype</code> property — an object that serves as the shared prototype for all instances created by that constructor.</p>
<pre><code class="language-js">// This is what JavaScript does internally:
Object.setPrototypeOf(obj, User.prototype);
// Or equivalently:
// obj.__proto__ = User.prototype;
</code></pre>
<p>This is the step that makes shared methods work. More on this shortly.</p>
<h3>Step 3: The constructor function runs with <code>this</code> set to the new object</h3>
<p>The function body of <code>User</code> executes, but with <code>this</code> pointing to the newly created object from step 1.</p>
<pre><code class="language-js">// With this = obj, the constructor body runs:
obj.name = "Priya";
obj.age = 28;
</code></pre>
<p>Every assignment to <code>this</code> inside the constructor becomes a property on the new object.</p>
<h3>Step 4: The new object is returned</h3>
<p>If the constructor does not explicitly return an object, JavaScript automatically returns the new object created in step 1. The result is what gets assigned to <code>user1</code>.</p>
<p>If the constructor <em>does</em> return an object explicitly, that object is returned instead of the new one. If it returns a primitive (a number, string, etc.), the return value is ignored and the new object is returned anyway. This edge case almost never comes up in practice — constructors do not usually return anything.</p>
<p>Putting it together:</p>
<pre><code class="language-js">function User(name, age) {
  // Step 1: new object created (internally)
  // Step 2: this.__proto__ = User.prototype (internally)

  // Step 3: constructor body runs with this = new object
  this.name = name;
  this.age = age;

  // Step 4: this is returned automatically
}

const user1 = new User("Priya", 28);
</code></pre>
<hr />
<h2>Prototype Linking: Shared Methods</h2>
<p>The reason <code>new</code> is worth understanding beyond just "it creates an object" is step 2 — the prototype link. This is what makes shared methods efficient.</p>
<p>You add shared methods to <code>Constructor.prototype</code>, and every instance automatically has access to them:</p>
<pre><code class="language-js">function User(name, age) {
  this.name = name;
  this.age = age;
}

User.prototype.greet = function() {
  console.log(`Hi, I'm \({this.name} and I'm \){this.age} years old.`);
};

User.prototype.isAdult = function() {
  return this.age &gt;= 18;
};

const user1 = new User("Priya", 28);
const user2 = new User("Aryan", 16);

user1.greet();        // Hi, I'm Priya and I'm 28 years old.
user2.greet();        // Hi, I'm Aryan and I'm 16 years old.

user1.isAdult();      // true
user2.isAdult();      // false
</code></pre>
<p><code>greet</code> and <code>isAdult</code> are defined once, on <code>User.prototype</code>. Both <code>user1</code> and <code>user2</code> access the same function objects. When you access <code>user1.greet</code>, JavaScript first looks for <code>greet</code> as an own property of <code>user1</code>, does not find it, then looks up the prototype chain and finds it on <code>User.prototype</code>.</p>
<p>You can verify this:</p>
<pre><code class="language-js">user1.hasOwnProperty("name");   // true  — own property
user1.hasOwnProperty("greet");  // false — inherited from prototype

user1.greet === user2.greet;    // true  — same function object
</code></pre>
<p>This is the key difference from the factory function approach. With factory functions, each object had its own copy of <code>greet</code>. With the constructor + prototype approach, every instance shares one copy. At scale — hundreds of instances — the memory difference is significant.</p>
<hr />
<h2>The Relationship Between Constructor and Instance</h2>
<p>Once an object is created with <code>new</code>, it carries a reference back to its constructor's prototype. You can inspect this:</p>
<pre><code class="language-js">console.log(Object.getPrototypeOf(user1) === User.prototype); // true
console.log(user1 instanceof User);                            // true
</code></pre>
<p><code>instanceof</code> checks whether <code>User.prototype</code> appears anywhere in the prototype chain of <code>user1</code>. Because of step 2, it always does for objects created with <code>new User(...)</code>.</p>
<p>The constructor function itself is also accessible:</p>
<pre><code class="language-js">console.log(user1.constructor === User); // true
</code></pre>
<p>This works because <code>User.prototype</code> has a <code>constructor</code> property pointing back to <code>User</code>, and <code>user1</code> inherits it through the prototype chain.</p>
<h3>Visualizing the links</h3>
<pre><code class="language-plaintext">user1
 ├── name: "Priya"        (own property)
 ├── age: 28              (own property)
 └── [[Prototype]] ──────► User.prototype
                              ├── greet: function
                              ├── isAdult: function
                              └── constructor ──► User
</code></pre>
<p><code>user1</code> owns <code>name</code> and <code>age</code>. It does not own <code>greet</code> or <code>isAdult</code> — it inherits them by following the <code>[[Prototype]]</code> link to <code>User.prototype</code>. <code>User.prototype</code> in turn has a <code>constructor</code> property that points back to the <code>User</code> function.</p>
<p>When JavaScript looks up a property:</p>
<ol>
<li><p>Check the object itself — own properties first.</p>
</li>
<li><p>If not found, follow <code>[[Prototype]]</code> to the next object in the chain.</p>
</li>
<li><p>Keep following the chain until the property is found or the chain ends at <code>null</code>.</p>
</li>
</ol>
<p>This chain is the prototype chain. Every object participates in it.</p>
<hr />
<h2>Adding to the Prototype After Creation</h2>
<p>Prototype methods can be added or changed at any time, and all existing instances immediately see the change:</p>
<pre><code class="language-js">function User(name, age) {
  this.name = name;
  this.age = age;
}

const user1 = new User("Priya", 28);

// Add a method after user1 already exists
User.prototype.introduce = function() {
  console.log(`My name is ${this.name}.`);
};

user1.introduce(); // My name is Priya.
</code></pre>
<p><code>user1</code> was created before <code>introduce</code> was defined. It can still call it because <code>introduce</code> is on <code>User.prototype</code>, and <code>user1</code>'s prototype link was set to <code>User.prototype</code> at creation time. Any change to that prototype object is reflected immediately in all instances.</p>
<p>This is powerful but requires care — modifying built-in prototypes like <code>Array.prototype</code> or <code>String.prototype</code> affects every array or string in your program and every library you use.</p>
<hr />
<h2>Instances Are Independent Objects</h2>
<p>Each instance created with <code>new</code> has its own copy of the properties set inside the constructor. Changing one instance's properties does not affect another:</p>
<pre><code class="language-js">function User(name, age) {
  this.name = name;
  this.age = age;
}

User.prototype.greet = function() {
  console.log(`Hi, I'm ${this.name}`);
};

const user1 = new User("Priya", 28);
const user2 = new User("Rahul", 34);

user1.name = "Meera"; // only changes user1

user1.greet(); // Hi, I'm Meera
user2.greet(); // Hi, I'm Rahul
</code></pre>
<p><code>user1.name</code> and <code>user2.name</code> are completely separate properties on completely separate objects. The prototype link is shared; the instance data is not.</p>
<hr />
<h2>What Happens Without <code>new</code></h2>
<p>This is an important edge case. If you forget <code>new</code> and call a constructor as a regular function:</p>
<pre><code class="language-js">function User(name, age) {
  this.name = name;
  this.age = age;
}

const user = User("Priya", 28); // forgot new
console.log(user); // undefined
</code></pre>
<p>The function runs, but without <code>new</code>, <code>this</code> is not a new object — in non-strict mode, it is the global object (<code>window</code> in browsers). The properties get added to <code>window.name</code> and <code>window.age</code> instead. The function returns <code>undefined</code> (no explicit return), so <code>user</code> is <code>undefined</code>.</p>
<p>In strict mode (<code>"use strict"</code>), <code>this</code> is <code>undefined</code> inside functions that are not called as methods, so you get a <code>TypeError</code> immediately:</p>
<pre><code class="language-js">"use strict";

function User(name, age) {
  this.name = name; // TypeError: Cannot set property 'name' of undefined
  this.age = age;
}

const user = User("Priya", 28);
</code></pre>
<p>The strict mode error is the better outcome — you find out about the mistake immediately rather than debugging mysterious global variable pollution.</p>
<h3>A guard against forgetting <code>new</code></h3>
<p>You can make a constructor safe to call either way:</p>
<pre><code class="language-js">function User(name, age) {
  if (!(this instanceof User)) {
    return new User(name, age);
  }
  this.name = name;
  this.age = age;
}

const user1 = new User("Priya", 28); // works
const user2 = User("Rahul", 34);     // also works — new is called internally
</code></pre>
<p>This is a pattern you see in older libraries that want to be forgiving about how they are called.</p>
<hr />
<h2>Constructor Functions vs ES6 Classes</h2>
<p>ES6 introduced the <code>class</code> syntax, which many JavaScript developers use today for object creation. It is important to understand that classes do not introduce a new object model — they are syntactic sugar over constructor functions and prototypes.</p>
<pre><code class="language-js">// Constructor function style
function User(name, age) {
  this.name = name;
  this.age = age;
}
User.prototype.greet = function() {
  console.log(`Hi, I'm ${this.name}`);
};

// Class style — identical behaviour, different syntax
class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  greet() {
    console.log(`Hi, I'm ${this.name}`);
  }
}
</code></pre>
<p>Both versions create the same prototype chain. Both are used with <code>new</code>. Both produce instances where <code>greet</code> lives on the prototype. The class syntax is cleaner and harder to misuse — methods defined inside a class body are automatically non-enumerable and the class itself cannot be called without <code>new</code>, throwing a <code>TypeError</code> immediately if you forget. But underneath, it is the same mechanism.</p>
<p>Understanding constructor functions and <code>new</code> directly means you understand what classes are doing, which matters when you read older code, debug prototype chain issues, or encounter interview questions that probe below the syntax level.</p>
<hr />
<h2>Putting It All Together: A Complete Example</h2>
<pre><code class="language-js">function Animal(name, sound) {
  this.name = name;
  this.sound = sound;
}

Animal.prototype.speak = function() {
  console.log(`\({this.name} says \){this.sound}!`);
};

Animal.prototype.describe = function() {
  console.log(`I am ${this.name}.`);
};

const dog = new Animal("Dog", "woof");
const cat = new Animal("Cat", "meow");
const cow = new Animal("Cow", "moo");

dog.speak();  // Dog says woof!
cat.speak();  // Cat says meow!
cow.speak();  // Cow says moo!

// All share the same speak function
console.log(dog.speak === cat.speak); // true
console.log(cat.speak === cow.speak); // true

// Own properties are independent
console.log(dog.hasOwnProperty("name"));  // true
console.log(dog.hasOwnProperty("speak")); // false

// instanceof works correctly
console.log(dog instanceof Animal); // true
console.log(cat instanceof Animal); // true

// Prototype chain is consistent
console.log(Object.getPrototypeOf(dog) === Animal.prototype); // true
</code></pre>
<p>Three objects, one constructor, one set of shared methods. That is the entire pattern.</p>
<hr />
<h2>Wrapping Up</h2>
<p>The <code>new</code> keyword is not magic — it is four well-defined steps:</p>
<ol>
<li><p>Create a new empty object.</p>
</li>
<li><p>Link that object's prototype to <code>Constructor.prototype</code>.</p>
</li>
<li><p>Run the constructor with <code>this</code> pointing to the new object.</p>
</li>
<li><p>Return the new object (unless the constructor returns a different object explicitly).</p>
</li>
</ol>
<p>Constructor functions define the shape of instances — the own properties each one gets. <code>Constructor.prototype</code> holds shared methods that all instances access through the prototype chain. Instances are independent objects sharing a common structure and a common set of inherited behaviours.</p>
<p>This is the foundation of object-oriented programming in JavaScript. ES6 classes make it more approachable, but they are describing the same underlying model. Know the model, and the syntax is just notation.</p>
]]></content:encoded></item><item><title><![CDATA[Callback Functions in JavaScript: How Asynchronous Code Really Works]]></title><description><![CDATA[Before you can understand callbacks, you need to accept one slightly strange idea about JavaScript: functions are values.
Not in a philosophical sense — in a completely literal, practical sense. A fun]]></description><link>https://blogs.arnabsamanta.in/callback-functions-in-javascript-how-asynchronous-code-really-works</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/callback-functions-in-javascript-how-asynchronous-code-really-works</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Sat, 28 Mar 2026 14:56:52 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/018f2482-de5b-4a33-8f31-732fc47678a2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before you can understand callbacks, you need to accept one slightly strange idea about JavaScript: functions are values.</p>
<p>Not in a philosophical sense — in a completely literal, practical sense. A function in JavaScript can be stored in a variable, put inside an array, attached to an object as a property, and most importantly, passed as an argument to another function. This is the foundation that callbacks are built on.</p>
<p>Once that clicks, callbacks are not mysterious at all. They are just functions that you hand to another function and say: "run this when you are done."</p>
<hr />
<h2>Functions as Values</h2>
<p>In most languages, a function is something you define and call. In JavaScript, it is also something you can <em>pass around</em>. Here is what that looks like:</p>
<pre><code class="language-js">function greet(name) {
  console.log(`Hello, ${name}!`);
}

// You can store a function in a variable
const sayHello = greet;

// And call it through the variable
sayHello("Priya"); // Hello, Priya!
</code></pre>
<p><code>sayHello</code> and <code>greet</code> now point to the same function. Neither call invokes anything — they just reference it. The <code>()</code> is what triggers the call.</p>
<p>This means you can also pass a function to another function:</p>
<pre><code class="language-js">function runTwice(fn) {
  fn();
  fn();
}

function sayHi() {
  console.log("Hi!");
}

runTwice(sayHi);
// Hi!
// Hi!
</code></pre>
<p><code>runTwice</code> does not know or care what <code>fn</code> does. It just calls it. This is the fundamental pattern behind every callback in JavaScript.</p>
<hr />
<h2>What Is a Callback Function?</h2>
<p>A callback is a function passed as an argument to another function, with the expectation that it will be called at some point — either immediately, or later when something happens.</p>
<pre><code class="language-js">function doSomething(callback) {
  console.log("Doing something...");
  callback(); // call the function that was passed in
}

function finished() {
  console.log("All done!");
}

doSomething(finished);
// Doing something...
// All done!
</code></pre>
<p><code>finished</code> is the callback here. It gets called by <code>doSomething</code> once its own work is complete. Notice that when you pass <code>finished</code> to <code>doSomething</code>, you write <code>finished</code> — not <code>finished()</code>. You are passing the function itself, not calling it. The call happens inside <code>doSomething</code>.</p>
<p>You can also write the callback inline as an anonymous function:</p>
<pre><code class="language-js">doSomething(function() {
  console.log("All done!");
});
</code></pre>
<p>Or as an arrow function:</p>
<pre><code class="language-js">doSomething(() =&gt; {
  console.log("All done!");
});
</code></pre>
<p>All three versions do the same thing. The inline style is common in modern JavaScript because you often write the callback right where you use it, without needing to name it separately.</p>
<hr />
<h2>Callbacks You Already Use</h2>
<p>Before getting into asynchronous code, it helps to look at callbacks in contexts you have almost certainly used already.</p>
<h3><code>Array.forEach()</code></h3>
<pre><code class="language-js">const fruits = ["mango", "banana", "guava"];

fruits.forEach(function(fruit) {
  console.log(fruit);
});
// mango
// banana
// guava
</code></pre>
<p>The function passed to <code>forEach</code> is a callback. <code>forEach</code> calls it once for each element in the array, passing the current element as an argument. You define <em>what to do with each item</em> — <code>forEach</code> handles <em>when</em> to call it.</p>
<h3><code>Array.map()</code></h3>
<pre><code class="language-js">const numbers = [1, 2, 3, 4];

const doubled = numbers.map(function(n) {
  return n * 2;
});

console.log(doubled); // [2, 4, 6, 8]
</code></pre>
<p>Same pattern. You pass a callback to <code>map</code>, and it calls your function for each element, collecting the return values into a new array. The callback defines the transformation; <code>map</code> defines the control flow.</p>
<h3><code>Array.filter()</code></h3>
<pre><code class="language-js">const scores = [45, 78, 91, 33, 60];

const passing = scores.filter(function(score) {
  return score &gt;= 50;
});

console.log(passing); // [78, 91, 60]
</code></pre>
<p>Again, a callback. You define the condition; <code>filter</code> decides what to keep.</p>
<p>These examples all use callbacks in a <em>synchronous</em> context — the callback runs immediately, right now, in the current flow of execution. But callbacks become truly essential when JavaScript needs to handle things that happen <em>later</em>.</p>
<hr />
<h2>Why Callbacks Exist: Asynchronous Programming</h2>
<p>JavaScript is single-threaded. That means it can only do one thing at a time. There is no parallel execution — just one task running, then the next.</p>
<p>This creates a problem. Some operations take time:</p>
<ul>
<li><p>Fetching data from a server</p>
</li>
<li><p>Reading a file from disk</p>
</li>
<li><p>Waiting for a user to click something</p>
</li>
<li><p>Setting a timer</p>
</li>
</ul>
<p>If JavaScript just waited for each of these to finish before moving on, the entire program would freeze. A button click would stop the UI from responding for two seconds while an API call completed. That is unacceptable for anything interactive.</p>
<p>JavaScript's solution is to hand off the slow operation and move on, leaving behind a callback that gets called when the operation eventually finishes. The rest of the program keeps running in the meantime.</p>
<h3><code>setTimeout</code> — the simplest async example</h3>
<pre><code class="language-js">console.log("Start");

setTimeout(function() {
  console.log("This runs after 2 seconds");
}, 2000);

console.log("End");
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Start
End
This runs after 2 seconds
</code></pre>
<p><code>setTimeout</code> takes a callback and a delay in milliseconds. It registers the callback to be called later and immediately returns — it does not wait. The program continues to the next line (<code>console.log("End")</code>), and only after 2000ms does the callback run.</p>
<p>This is the core idea: the callback is called not when you write it, but when the time comes.</p>
<h3><code>setInterval</code> — repeating callbacks</h3>
<pre><code class="language-js">let count = 0;

const intervalId = setInterval(function() {
  count++;
  console.log(`Tick ${count}`);
  if (count === 3) {
    clearInterval(intervalId);
  }
}, 1000);
</code></pre>
<p>Output:</p>
<pre><code class="language-plaintext">Tick 1   (after 1 second)
Tick 2   (after 2 seconds)
Tick 3   (after 3 seconds)
</code></pre>
<p>The callback runs repeatedly on a schedule. <code>clearInterval</code> stops it.</p>
<hr />
<h2>Passing Functions as Arguments: A Closer Look</h2>
<p>Let's slow down and look at exactly what happens when you pass a function as an argument.</p>
<pre><code class="language-js">function fetchData(url, onSuccess, onError) {
  // imagine this actually fetches something
  const success = true;

  if (success) {
    onSuccess({ id: 1, name: "Rahul" });
  } else {
    onError("Network error");
  }
}

function handleSuccess(data) {
  console.log("Got data:", data);
}

function handleError(message) {
  console.log("Error:", message);
}

fetchData("https://api.example.com/user", handleSuccess, handleError);
// Got data: { id: 1, name: 'Rahul' }
</code></pre>
<p><code>fetchData</code> receives two callback functions: one for success, one for failure. It decides which one to call based on the outcome. The caller defines what should happen in each case; <code>fetchData</code> defines when to trigger them.</p>
<p>This pattern — passing multiple callbacks for different outcomes — was standard before Promises existed, and you still see it in Node.js core APIs and older libraries.</p>
<h3>Callbacks with arguments</h3>
<p>The calling function can pass arguments to the callback when it calls it. This is how <code>forEach</code>, <code>map</code>, and <code>filter</code> give you the current element:</p>
<pre><code class="language-js">function repeat(times, callback) {
  for (let i = 0; i &lt; times; i++) {
    callback(i); // passes the current index to the callback
  }
}

repeat(3, function(index) {
  console.log(`Iteration ${index}`);
});
// Iteration 0
// Iteration 1
// Iteration 2
</code></pre>
<p>The callback does not pull the index from somewhere — <code>repeat</code> hands it over when calling the function. You define what to do with it.</p>
<hr />
<h2>Callback Usage in Common Scenarios</h2>
<h3>Event listeners</h3>
<p>Callbacks are fundamental to browser event handling. When a user does something, you want code to run. You register a callback for that event:</p>
<pre><code class="language-js">const button = document.querySelector("#submit");

button.addEventListener("click", function(event) {
  console.log("Button clicked!", event.target);
});
</code></pre>
<p>The callback runs when the user clicks. Not before. Not on a timer. Specifically when that event fires. The browser calls your function and passes an event object with details about what happened.</p>
<pre><code class="language-js">document.addEventListener("keydown", function(event) {
  if (event.key === "Enter") {
    console.log("Enter pressed");
  }
});
</code></pre>
<p>You can register multiple listeners on the same element. Each callback runs independently when the event occurs.</p>
<h3>File reading in Node.js</h3>
<pre><code class="language-js">const fs = require("fs");

fs.readFile("data.txt", "utf8", function(error, contents) {
  if (error) {
    console.log("Could not read file:", error.message);
    return;
  }
  console.log("File contents:", contents);
});

console.log("This runs before the file is read");
</code></pre>
<p><code>fs.readFile</code> starts reading the file and returns immediately. When the file is ready (or an error occurs), it calls your callback with either an error or the file contents. The convention in Node.js is <code>(error, result)</code> — always check the error first.</p>
<h3>HTTP requests (the old way)</h3>
<pre><code class="language-js">function getUser(userId, callback) {
  const xhr = new XMLHttpRequest();
  xhr.open("GET", `https://api.example.com/users/${userId}`);

  xhr.onload = function() {
    if (xhr.status === 200) {
      callback(null, JSON.parse(xhr.responseText));
    } else {
      callback(new Error(`Request failed: ${xhr.status}`));
    }
  };

  xhr.onerror = function() {
    callback(new Error("Network error"));
  };

  xhr.send();
}

getUser(1, function(error, user) {
  if (error) {
    console.log("Error:", error.message);
    return;
  }
  console.log("User:", user.name);
});
</code></pre>
<p>This is how JavaScript handled HTTP requests before <code>fetch</code> and Promises. The callback-based XHR API is verbose, but it follows the same pattern: start the operation, register a callback, let it run when ready.</p>
<hr />
<h2>The Callback Nesting Problem</h2>
<p>Callbacks work cleanly for a single async operation. The trouble starts when you need several operations in sequence, where each one depends on the result of the previous one.</p>
<p>Imagine you need to:</p>
<ol>
<li><p>Fetch a user by ID</p>
</li>
<li><p>Use the user's ID to fetch their orders</p>
</li>
<li><p>Use an order ID to fetch the order details</p>
</li>
</ol>
<p>With callbacks, this looks like:</p>
<pre><code class="language-js">getUser(1, function(error, user) {
  if (error) {
    console.log("Error fetching user:", error.message);
    return;
  }

  getOrders(user.id, function(error, orders) {
    if (error) {
      console.log("Error fetching orders:", error.message);
      return;
    }

    getOrderDetails(orders[0].id, function(error, details) {
      if (error) {
        console.log("Error fetching details:", error.message);
        return;
      }

      console.log("Order details:", details);
    });
  });
});
</code></pre>
<p>Each async step pushes the code one level deeper. Add another step, and you add another level of indentation. This pattern has a name: <strong>callback hell</strong>, sometimes called the <strong>pyramid of doom</strong> — because the code forms a triangle of ever-deepening nesting as it grows to the right.</p>
<pre><code class="language-plaintext">getUser(
  getOrders(
    getOrderDetails(
      processPayment(
        sendConfirmation(
          // we have lost the thread entirely
        )
      )
    )
  )
)
</code></pre>
<p>The problems with deeply nested callbacks are real:</p>
<p><strong>Error handling is repeated.</strong> Each level needs its own error check. If you forget one, errors silently disappear. If you want consistent error handling, you duplicate the same pattern at every level.</p>
<p><strong>The logic is hard to follow.</strong> The sequence of operations is obvious in plain English: get user, then get orders, then get details. In nested callbacks, that sequence is encoded in the <em>nesting structure</em> rather than in the reading order of the code. You have to trace the indentation levels to understand what happens when.</p>
<p><strong>Refactoring is painful.</strong> To change the order of operations, or to add a step in the middle, you restructure the nesting — which means touching every level of the code.</p>
<p><strong>Reusability suffers.</strong> The logic at each level is buried inside a callback, not in a named, reusable function. Extracting a piece of it means untangling the nesting first.</p>
<h3>A partial fix: named callbacks</h3>
<p>One way to reduce the visual nesting is to name each callback and move it out of the inline position:</p>
<pre><code class="language-js">function handleDetails(error, details) {
  if (error) { console.log("Error:", error.message); return; }
  console.log("Order details:", details);
}

function handleOrders(error, orders) {
  if (error) { console.log("Error:", error.message); return; }
  getOrderDetails(orders[0].id, handleDetails);
}

function handleUser(error, user) {
  if (error) { console.log("Error:", error.message); return; }
  getOrders(user.id, handleOrders);
}

getUser(1, handleUser);
</code></pre>
<p>This reads top-to-bottom. The nesting is gone. But the logic is now fragmented across four separate functions that only make sense together. You gain readability but lose cohesion. The code is less deeply nested and more confusing to trace as a whole.</p>
<p>This is the ceiling of what callbacks can offer for sequential async code. It is good enough for simple cases, and genuinely problematic for complex ones.</p>
<hr />
<h2>The Flow of a Callback</h2>
<p>To make the execution order concrete, here is exactly what happens in a simple async callback scenario:</p>
<pre><code class="language-js">console.log("1. Start");

setTimeout(function() {
  console.log("3. Inside callback (runs after 1 second)");
}, 1000);

console.log("2. After setTimeout");
</code></pre>
<p>Step by step:</p>
<ol>
<li><p><code>"1. Start"</code> is logged — synchronous, runs immediately.</p>
</li>
<li><p><code>setTimeout</code> is called. JavaScript registers the callback with a 1-second timer and moves on. The callback is not called yet.</p>
</li>
<li><p><code>"2. After setTimeout"</code> is logged — synchronous, runs immediately.</p>
</li>
<li><p>The current synchronous code is done. JavaScript checks the timer.</p>
</li>
<li><p>After 1 second, the timer fires. JavaScript calls the registered callback.</p>
</li>
<li><p><code>"3. Inside callback"</code> is logged.</p>
</li>
</ol>
<p>The key point: steps 1–3 happen in sequence without any pause. Step 6 happens separately, after the main thread has finished. This is the event loop at work — JavaScript handles synchronous code first, then processes queued callbacks.</p>
<hr />
<h2>Wrapping Up</h2>
<p>Callbacks are the original building block of asynchronous JavaScript. They are how the language handles anything that takes time — network requests, timers, user events, file operations — without freezing everything while it waits.</p>
<p>The concept is simple: pass a function, get it called later. The pattern appears everywhere, from <code>forEach</code> to <code>addEventListener</code> to Node.js APIs. Understanding callbacks is not optional — it is the prerequisite for understanding everything else in async JavaScript.</p>
<p>The nesting problem is real, and it is solved by Promises and <code>async/await</code>, which are built on exactly the same idea but expose it with a cleaner interface. Before tackling those, getting comfortable with callbacks gives you the mental model that makes Promises feel like a natural evolution rather than a new concept entirely.</p>
]]></content:encoded></item><item><title><![CDATA[Template Literals in JavaScript: Write Strings the Modern Way]]></title><description><![CDATA[Every JavaScript developer has written something like this:
var greeting = "Hello, " + firstName + " " + lastName + "! You have " + count + " messages.";

It works. But it is painful to read, painful ]]></description><link>https://blogs.arnabsamanta.in/template-literals-in-javascript-write-strings-the-modern-way</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/template-literals-in-javascript-write-strings-the-modern-way</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Sat, 28 Mar 2026 14:44:59 GMT</pubDate><content:encoded><![CDATA[<p>Every JavaScript developer has written something like this:</p>
<pre><code class="language-js">var greeting = "Hello, " + firstName + " " + lastName + "! You have " + count + " messages.";
</code></pre>
<p>It works. But it is painful to read, painful to write, and painful to debug when something goes wrong. Add a missing space, forget a closing quote, or nest a few more variables in, and you are staring at a wall of plus signs trying to find the bug.</p>
<p>Template literals, introduced in ES6, replace this entire pattern with something clean, readable, and far more powerful. This guide covers everything you need to know — from the basic syntax to real-world use cases — with a close look at how much simpler your strings become.</p>
<hr />
<h2>The Problem with Traditional String Concatenation</h2>
<p>Before template literals, JavaScript had two ways to write strings: single quotes and double quotes. Both share the same fundamental limitation — they cannot contain dynamic values. To embed a variable, you break out of the string, use the <code>+</code> operator, and then start a new string literal.</p>
<p>This gets unwieldy fast.</p>
<pre><code class="language-js">// A simple greeting
var name = "Priya";
var age = 28;
var city = "Kolkata";

var bio = "My name is " + name + ", I am " + age + " years old, and I live in " + city + ".";
</code></pre>
<p>Count the quotes. Count the plus signs. Now imagine adding two more variables. The problems compound:</p>
<p><strong>Readability collapses.</strong> The actual message you are trying to construct is buried inside a thicket of operators and delimiters. You cannot glance at the code and immediately understand what string it produces.</p>
<p><strong>Spacing errors are invisible.</strong> A missing space before or after a variable — <code>"Hello,"+ name</code> vs <code>"Hello, " + name</code> — produces a bug that is easy to miss in a code review.</p>
<p><strong>Multi-line strings require hacks.</strong> If you want a string that spans multiple lines, you either concatenate with <code>\n</code> escape sequences, or use backslash continuation — both of which are fragile and hard to read:</p>
<pre><code class="language-js">var html = "&lt;div class=\"card\"&gt;\n" +
           "  &lt;h2&gt;" + title + "&lt;/h2&gt;\n" +
           "  &lt;p&gt;" + description + "&lt;/p&gt;\n" +
           "&lt;/div&gt;";
</code></pre>
<p>That backslash-n approach works, but it looks nothing like the HTML it produces. Anyone reading this code has to mentally reconstruct the output.</p>
<p><strong>Quote conflicts are constant.</strong> If your string contains a single quote, you use double quotes as the delimiter, and vice versa. If it contains both, you reach for backslash escapes:</p>
<pre><code class="language-js">var message = "It's a \"great\" day";
var other   = 'It\'s a "great" day';
</code></pre>
<p>Template literals solve all of these problems in one move.</p>
<hr />
<h2>Template Literal Syntax</h2>
<p>A template literal uses backticks <code>`</code> instead of single or double quotes. That is the only delimiter change — but it unlocks an entirely different set of capabilities.</p>
<pre><code class="language-js">const greeting = `Hello, world`;
</code></pre>
<p>On its own, this is identical to <code>"Hello, world"</code>. The power comes from what you can put inside.</p>
<h3>String interpolation with <code>${}</code></h3>
<p>To embed any JavaScript expression inside a template literal, wrap it in <code>${}</code>:</p>
<pre><code class="language-js">const name = "Arjun";
const greeting = `Hello, ${name}!`;
// "Hello, Arjun!"
</code></pre>
<p>The expression inside <code>${}</code> is evaluated at runtime and its result is converted to a string and inserted. It is not limited to simple variables — any valid JavaScript expression works:</p>
<pre><code class="language-js">const a = 10;
const b = 3;

`\({a} + \){b} = ${a + b}`          // "10 + 3 = 13"
`${a &gt; b ? "greater" : "smaller"}` // "greater"
`${[1, 2, 3].join(", ")}`          // "1, 2, 3"
`${"hello".toUpperCase()}`          // "HELLO"
</code></pre>
<p>The <code>${}</code> syntax turns your string into a live template. You write the message naturally, and the values drop in where they belong.</p>
<hr />
<h2>Before vs After: The Difference in Practice</h2>
<p>Looking at the same string written both ways is the clearest way to understand what template literals change.</p>
<h3>Simple variable embedding</h3>
<pre><code class="language-js">const user = "Meera";
const score = 94;

// Before
const result = "Well done, " + user + "! Your score is " + score + " out of 100.";

// After
const result = `Well done, \({user}! Your score is \){score} out of 100.`;
</code></pre>
<p>The after version reads like natural language. The structure of the sentence is visible without having to mentally parse the concatenation.</p>
<h3>Expressions inside strings</h3>
<pre><code class="language-js">const price = 250;
const quantity = 3;
const tax = 0.18;

// Before
var total = "Total: Rs. " + (price * quantity * (1 + tax)).toFixed(2);

// After
const total = `Total: Rs. ${(price * quantity * (1 + tax)).toFixed(2)}`;
</code></pre>
<p>Inline expressions are cleaner in template literals because the expression is a natural part of the string — you do not need to construct the expression separately and concatenate it.</p>
<h3>HTML strings</h3>
<pre><code class="language-js">const product = { name: "Mechanical Keyboard", price: 3500, rating: 4.7 };

// Before
var card = "&lt;div class=\"product\"&gt;" +
           "&lt;h3&gt;" + product.name + "&lt;/h3&gt;" +
           "&lt;p&gt;Rs. " + product.price + "&lt;/p&gt;" +
           "&lt;span&gt;" + product.rating + " stars&lt;/span&gt;" +
           "&lt;/div&gt;";

// After
const card = `
  &lt;div class="product"&gt;
    &lt;h3&gt;${product.name}&lt;/h3&gt;
    &lt;p&gt;Rs. ${product.price}&lt;/p&gt;
    &lt;span&gt;${product.rating} stars&lt;/span&gt;
  &lt;/div&gt;
`;
</code></pre>
<p>The after version looks like actual HTML. You can read it, modify it, and reason about it the same way you would a real template. Notice also that double quotes inside the string require no escaping — backticks do not conflict with them.</p>
<hr />
<h2>Multi-line Strings</h2>
<p>This is where template literals save the most frustration. A backtick string can simply span multiple lines — the newlines are preserved in the output.</p>
<pre><code class="language-js">const poem = `Roses are red,
Violets are blue,
Template literals are clean,
And so is this haiku.`;
</code></pre>
<p>That is it. No <code>\n</code>. No string concatenation. No backslash continuation. The string you write is the string you get.</p>
<p>Compare this to the old approach, where you had to manually encode every line break:</p>
<pre><code class="language-js">// Before: you had to think about line breaks explicitly
var poem = "Roses are red,\n" +
           "Violets are blue,\n" +
           "Template literals are clean,\n" +
           "And so is this haiku.";
</code></pre>
<p>The before version requires you to remember <code>\n</code> at the end of every line, keep the concatenation operators consistent, and mentally reconstruct what the output looks like. The after version is self-documenting.</p>
<h3>Practical multi-line use: HTML templates</h3>
<pre><code class="language-js">function renderUserCard(user) {
  return `
    &lt;div class="user-card"&gt;
      &lt;img src="\({user.avatar}" alt="\){user.name}" /&gt;
      &lt;div class="user-info"&gt;
        &lt;h2&gt;${user.name}&lt;/h2&gt;
        &lt;p&gt;${user.bio}&lt;/p&gt;
        &lt;a href="mailto:\({user.email}"&gt;\){user.email}&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  `;
}
</code></pre>
<p>You can read this function and immediately understand what HTML it produces. That was nearly impossible with the concatenation approach.</p>
<h3>Practical multi-line use: SQL queries</h3>
<pre><code class="language-js">const query = `
  SELECT users.name, orders.total
  FROM users
  JOIN orders ON users.id = orders.user_id
  WHERE orders.created_at &gt; '${startDate}'
    AND orders.status = 'completed'
  ORDER BY orders.total DESC
  LIMIT ${limit}
`;
</code></pre>
<p>SQL written this way is indented properly, readable at a glance, and easy to edit. With concatenation, SQL queries become nearly incomprehensible.</p>
<hr />
<h2>Nesting Template Literals</h2>
<p>Template literals can be nested — you can have a template literal inside <code>${}</code>:</p>
<pre><code class="language-js">const items = ["Mango", "Banana", "Guava"];

const list = `
  &lt;ul&gt;
    \({items.map(item =&gt; `&lt;li&gt;\){item}&lt;/li&gt;`).join("\n    ")}
  &lt;/ul&gt;
`;
</code></pre>
<p>Output:</p>
<pre><code class="language-html">&lt;ul&gt;
  &lt;li&gt;Mango&lt;/li&gt;
  &lt;li&gt;Banana&lt;/li&gt;
  &lt;li&gt;Guava&lt;/li&gt;
&lt;/ul&gt;
</code></pre>
<p>This is a pattern you will use frequently when building HTML or JSX dynamically. The outer template provides the structure, and the inner template handles each item in the list.</p>
<hr />
<h2>Tagged Template Literals</h2>
<p>Template literals have one more capability that goes beyond string construction: <em>tagging</em>. A tagged template is a function that receives the template's parts and interpolated values as separate arguments, letting you control how the string is assembled.</p>
<pre><code class="language-js">function highlight(strings, ...values) {
  return strings.reduce((result, str, i) =&gt; {
    return result + str + (values[i] !== undefined ? `&lt;mark&gt;${values[i]}&lt;/mark&gt;` : "");
  }, "");
}

const name = "Rahul";
const role = "engineer";

highlight`Meet \({name}, a software \){role}.`
// "Meet &lt;mark&gt;Rahul&lt;/mark&gt;, a software &lt;mark&gt;engineer&lt;/mark&gt;."
</code></pre>
<p>The tag function (<code>highlight</code>) receives:</p>
<ul>
<li><p><code>strings</code>: an array of the static string parts — <code>["Meet ", ", a software ", "."]</code></p>
</li>
<li><p><code>...values</code>: the interpolated values — <code>["Rahul", "engineer"]</code></p>
</li>
</ul>
<p>You interleave them however you like. This is how libraries like <code>styled-components</code> and <code>sql-template-strings</code> work under the hood — they use tagged templates to process interpolated values with custom logic.</p>
<h3>A practical tag: safe SQL</h3>
<p>A common and important use of tagged templates is preventing SQL injection by escaping values:</p>
<pre><code class="language-js">function safeSQL(strings, ...values) {
  const escaped = values.map(v =&gt; `'${String(v).replace(/'/g, "''")}'`);
  return strings.reduce((q, str, i) =&gt; q + str + (escaped[i] ?? ""), "");
}

const userId = "1 OR 1=1";  // injection attempt
safeSQL`SELECT * FROM users WHERE id = ${userId}`;
// "SELECT * FROM users WHERE id = '1 OR 1=1'"  — safely escaped
</code></pre>
<p>The value is treated as a literal string, not executable SQL, because the tag function controls how it is inserted.</p>
<hr />
<h2>Use Cases in Modern JavaScript</h2>
<p>Template literals appear throughout modern JavaScript and its ecosystem. Here are the patterns you will encounter most often.</p>
<h3>Dynamic URLs and API endpoints</h3>
<pre><code class="language-js">const baseURL = "https://api.example.com";
const version = "v2";
const userId = 42;

const endpoint = `\({baseURL}/\){version}/users/${userId}/orders`;
// "https://api.example.com/v2/users/42/orders"
</code></pre>
<p>This is far easier to read than building URLs with concatenation, and far less error-prone — missing a slash between segments is immediately visible.</p>
<h3>Error messages and logging</h3>
<pre><code class="language-js">function validateAge(age) {
  if (age &lt; 0 || age &gt; 120) {
    throw new Error(`Invalid age: ${age}. Expected a value between 0 and 120.`);
  }
}
</code></pre>
<p>Error messages written as template literals carry the actual bad value, making them useful for debugging without any extra logging effort.</p>
<h3>Conditional strings</h3>
<pre><code class="language-js">const count = 3;
const message = `You have \({count} new \){count === 1 ? "notification" : "notifications"}.`;
// "You have 3 new notifications."
</code></pre>
<p>Ternary expressions inside <code>${}</code> handle pluralization and conditional text cleanly — no need to assemble the string in multiple steps.</p>
<h3>CSS-in-JS</h3>
<p>Libraries like <code>styled-components</code> use tagged template literals to write CSS directly in JavaScript:</p>
<pre><code class="language-js">import styled from "styled-components";

const Button = styled.button`
  background: ${props =&gt; props.primary ? "#0070f3" : "white"};
  color: ${props =&gt; props.primary ? "white" : "#0070f3"};
  padding: 0.5rem 1.25rem;
  border-radius: 4px;
`;
</code></pre>
<p>The CSS is readable, the dynamic values are natural, and the tag function handles the rest. This pattern would be completely impractical with concatenation.</p>
<h3>Building email or notification templates</h3>
<pre><code class="language-js">function buildEmailBody({ recipientName, senderName, orderId, total }) {
  return `
    Hi ${recipientName},

    Your order #${orderId} has been confirmed.

    Order summary:
    - Total charged: Rs. ${total}

    Thank you for shopping with us.

    Best regards,
    ${senderName}
  `.trim();
}
</code></pre>
<p>The template reads exactly like the email it will produce. Editing it is intuitive — you do not need to parse concatenation operators to understand the structure.</p>
<hr />
<h2>Things to Be Careful About</h2>
<p><strong>Whitespace is literal.</strong> Every space, tab, and newline in a template literal is part of the string. If you indent a template inside a function for readability, that indentation ends up in the output. Use <code>.trim()</code> to strip leading and trailing whitespace, or be deliberate about your indentation.</p>
<p><strong>Backticks inside template literals need escaping.</strong> If your string itself needs to contain a backtick, escape it with a backslash:</p>
<pre><code class="language-js">const code = `Use backticks like \` this \` in template literals.`;
</code></pre>
<p><strong>Do not put complex logic inside</strong> <code>\({}</code><strong>.</strong> The <code>\){}</code> block is for expressions, not statements. Multi-step logic belongs in a variable outside the template:</p>
<pre><code class="language-js">// Harder to read — logic crammed into the template
const msg = `Status: ${(() =&gt; { if (a &gt; b) return "high"; if (a &lt; b) return "low"; return "equal"; })()}`;

// Better — compute it separately
const status = a &gt; b ? "high" : a &lt; b ? "low" : "equal";
const msg = `Status: ${status}`;
</code></pre>
<p><strong>Template literals are not magic performance boosters.</strong> They are syntactic sugar — at runtime, they produce the same string. Choose them for readability, not performance.</p>
<hr />
<h2>Quick Reference</h2>
<pre><code class="language-js">// Basic interpolation
`Hello, ${name}!`

// Expressions
`\({a + b}`, `\){condition ? "yes" : "no"}`, `${arr.join(", ")}`

// Multi-line
`Line one
Line two
Line three`

// Nested templates
`&lt;ul&gt;\({items.map(i =&gt; `&lt;li&gt;\){i}&lt;/li&gt;`).join("")}&lt;/ul&gt;`

// Tagged templates
tag`string with ${value} interpolated`

// Escaping backticks
`backtick: \``

// Stripping indentation whitespace
`
  content here
`.trim()
</code></pre>
<hr />
<h2>Wrapping Up</h2>
<p>Template literals are one of the highest-value additions in modern JavaScript. The improvement in readability alone justifies switching — but the additional capabilities, from multiline strings to tagged templates, make them genuinely more powerful than what they replace.</p>
<p>The migration is straightforward: anywhere you use string concatenation with variables, a template literal is almost certainly the better choice. It reads like the output it produces. The intent is clear. The bugs are easier to spot.</p>
<p>Start replacing <code>+</code> with <code>${}</code> today, and you will quickly wonder how you tolerated the old way for so long.</p>
]]></content:encoded></item><item><title><![CDATA[Flattening Arrays in JavaScript: A Complete Guide with Interview Scenarios]]></title><description><![CDATA[Arrays are one of the most fundamental data structures in JavaScript. You use them constantly — for lists of users, collections of IDs, API responses, and more. But real-world data is rarely flat. You]]></description><link>https://blogs.arnabsamanta.in/flattening-arrays-in-javascript-a-complete-guide-with-interview-scenarios</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/flattening-arrays-in-javascript-a-complete-guide-with-interview-scenarios</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Sat, 28 Mar 2026 14:41:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/5a6595fd-a9ce-4263-94a3-55a63f761be9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Arrays are one of the most fundamental data structures in JavaScript. You use them constantly — for lists of users, collections of IDs, API responses, and more. But real-world data is rarely flat. You often end up with arrays that contain other arrays, which contain more arrays, nested several levels deep. Before you can work with that data meaningfully, you need to flatten it.</p>
<p>This guide walks through what nested arrays are, why flattening matters, and every practical technique you should know — including the ones that show up in interviews.</p>
<hr />
<h2>What Is a Nested Array?</h2>
<p>A nested array is simply an array that contains one or more arrays as its elements. Those inner arrays can themselves contain arrays, and so on.</p>
<pre><code class="language-js">// One level deep
const oneLevel = [1, [2, 3], [4, 5]];

// Two levels deep
const twoLevels = [1, [2, [3, 4]], [5, [6, 7]]];

// Arbitrarily deep
const deep = [1, [2, [3, [4, [5]]]]];
</code></pre>
<p>Visually, think of it like boxes inside boxes:</p>
<pre><code class="language-plaintext">outerArray
└── [ 1, innerArray, innerArray ]
         └── [ 2, deepArray ]
                   └── [ 3, 4 ]   ← leaf values
</code></pre>
<p>Each level adds a layer of nesting. The actual values — numbers, strings, objects — live at the innermost level. To get at them without worrying about the structure, you need to flatten.</p>
<hr />
<h2>Why Does Flattening Matter?</h2>
<p>Nested arrays come up naturally whenever data is hierarchical or composed from multiple sources. Here are the situations where you will encounter them most often:</p>
<p><strong>API responses.</strong> A response might return paginated chunks, each being an array. You fetch three pages and end up with <code>[[...], [...], [...]]</code> — three arrays you need to merge into one.</p>
<p><strong>Tree-shaped data.</strong> Categories with subcategories, comments with replies, folder structures — all of these are naturally recursive and often arrive pre-nested.</p>
<p><code>Array.map()</code> <strong>producing arrays.</strong> If you <code>map</code> over a list and each callback returns an array, you get an array of arrays instead of a single flat result. This is the most common accidental nesting in everyday JavaScript.</p>
<pre><code class="language-js">const sentences = ["hello world", "foo bar"];
const words = sentences.map(s =&gt; s.split(" "));
// [["hello", "world"], ["foo", "bar"]]
// You wanted: ["hello", "world", "foo", "bar"]
</code></pre>
<p><strong>Set operations.</strong> Grouping, partitioning, or combining arrays by some criteria produces nested structures you later need to linearize.</p>
<p>In all these cases, working with a single, flat array is far simpler — easier to iterate, filter, search, and pass around.</p>
<hr />
<h2>The Concept of Flattening</h2>
<p>Flattening means taking a nested array and producing a new array that contains all the same values, but without any nesting. Every inner array is "unwrapped" so its elements become direct children of the result.</p>
<pre><code class="language-plaintext">Input:   [1, [2, 3], [4, [5, 6]]]
                              ↓  flatten
Output:  [1, 2, 3, 4, 5, 6]
</code></pre>
<p>The key decision when flattening is <em>depth</em> — how many levels of nesting to remove:</p>
<ul>
<li><p><strong>Depth 1</strong>: unwrap only the outermost arrays. Inner arrays that are nested deeper remain.</p>
</li>
<li><p><strong>Depth Infinity</strong>: unwrap everything, no matter how deep.</p>
</li>
<li><p><strong>Specific depth (2, 3, ...)</strong>: unwrap exactly that many levels.</p>
</li>
</ul>
<pre><code class="language-js">const arr = [1, [2, [3, [4]]]];

arr.flat(1);        // [1, 2, [3, [4]]]   — one level removed
arr.flat(2);        // [1, 2, 3, [4]]     — two levels removed
arr.flat(Infinity); // [1, 2, 3, 4]       — fully flat
</code></pre>
<p>With that mental model in place, let's look at every approach available.</p>
<hr />
<h2>Approach 1: <code>Array.flat()</code> — the modern standard</h2>
<p>Introduced in ES2019, <code>Array.flat()</code> is the cleanest and most readable way to flatten arrays. It takes an optional depth argument (default is <code>1</code>) and returns a new flattened array without mutating the original.</p>
<pre><code class="language-js">const arr = [1, [2, 3], [4, [5, 6]]];

arr.flat();         // [1, 2, 3, 4, [5, 6]]
arr.flat(2);        // [1, 2, 3, 4, 5, 6]
arr.flat(Infinity); // [1, 2, 3, 4, 5, 6]
</code></pre>
<h3>When depth is unknown</h3>
<p>If you do not know how deep the nesting goes, use <code>Infinity</code>:</p>
<pre><code class="language-js">const unknown = [1, [2, [3, [4, [5]]]]];
unknown.flat(Infinity); // [1, 2, 3, 4, 5]
</code></pre>
<h3><code>flatMap()</code> — map and flatten in one step</h3>
<p><code>Array.flatMap()</code> combines <code>map()</code> and <code>flat(1)</code> into a single operation. It is perfect for the case where your mapping function returns arrays.</p>
<pre><code class="language-js">const sentences = ["hello world", "foo bar"];
sentences.flatMap(s =&gt; s.split(" "));
// ["hello", "world", "foo", "bar"]
</code></pre>
<p>This is both more readable and more performant than <code>sentences.map(...).flat()</code> because it only makes one pass over the data.</p>
<p><strong>Compatibility note:</strong> <code>flat()</code> and <code>flatMap()</code> are supported in all modern browsers and Node.js 11+. If you target older environments, use one of the approaches below.</p>
<hr />
<h2>Approach 2: <code>reduce()</code> + <code>concat()</code> — one level</h2>
<p>Before <code>flat()</code> existed, this was the idiomatic way to flatten one level of nesting. It is worth understanding because it appears frequently in older codebases and in interviews.</p>
<pre><code class="language-js">function flattenOneLevel(arr) {
  return arr.reduce((acc, val) =&gt; acc.concat(val), []);
}

flattenOneLevel([1, [2, 3], [4, 5]]); // [1, 2, 3, 4, 5]
</code></pre>
<p>Step by step, here is what happens:</p>
<pre><code class="language-plaintext">Start:    acc = []
Step 1:   acc.concat(1)      → [1]
Step 2:   acc.concat([2, 3]) → [1, 2, 3]
Step 3:   acc.concat([4, 5]) → [1, 2, 3, 4, 5]
</code></pre>
<p><code>concat</code> handles both single values and arrays correctly, which is why this pattern works cleanly. The limitation is that it only flattens one level — if an element is <code>[2, [3, 4]]</code>, the <code>[3, 4]</code> stays nested.</p>
<hr />
<h2>Approach 3: Spread operator + <code>concat()</code> — one level</h2>
<p>A slightly more concise version of the same idea:</p>
<pre><code class="language-js">function flattenOneLevel(arr) {
  return [].concat(...arr);
}

flattenOneLevel([1, [2, 3], [4, 5]]); // [1, 2, 3, 4, 5]
</code></pre>
<p>The spread operator unpacks <code>arr</code> into individual arguments to <code>concat</code>. Since <code>concat</code> accepts both arrays and non-arrays, this has the same effect as the <code>reduce</code> version. It is terse and readable for one-level flattening.</p>
<hr />
<h2>Approach 4: Recursion — any depth</h2>
<p>When you need full depth flattening and cannot use <code>flat(Infinity)</code> — or when an interviewer wants to see you implement it yourself — recursion is the natural solution.</p>
<pre><code class="language-js">function flattenDeep(arr) {
  return arr.reduce((acc, val) =&gt; {
    if (Array.isArray(val)) {
      return acc.concat(flattenDeep(val));
    }
    return acc.concat(val);
  }, []);
}

flattenDeep([1, [2, [3, [4, [5]]]]]); // [1, 2, 3, 4, 5]
</code></pre>
<p>The logic is:</p>
<ul>
<li><p>Walk through each element.</p>
</li>
<li><p>If it is an array, recurse into it (flatten it the same way).</p>
</li>
<li><p>If it is a plain value, add it to the accumulator.</p>
</li>
</ul>
<p>You can also write this more concisely with <code>flatMap</code>:</p>
<pre><code class="language-js">function flattenDeep(arr) {
  return arr.flatMap(val =&gt;
    Array.isArray(val) ? flattenDeep(val) : val
  );
}
</code></pre>
<p>Both do the same thing. The second form is cleaner once you are comfortable with <code>flatMap</code>.</p>
<hr />
<h2>Approach 5: Iterative with a stack — no recursion</h2>
<p>Recursive solutions can hit the call stack limit on extremely deep arrays. The iterative approach using a stack avoids this entirely. This is the solution that impresses in technical interviews.</p>
<pre><code class="language-js">function flattenIterative(arr) {
  const stack = [...arr];
  const result = [];

  while (stack.length &gt; 0) {
    const val = stack.pop();
    if (Array.isArray(val)) {
      stack.push(...val);
    } else {
      result.push(val);
    }
  }

  return result.reverse();
}

flattenIterative([1, [2, [3, [4]]]]); // [1, 2, 3, 4]
</code></pre>
<p>Here is how it works step by step on <code>[1, [2, [3]]]</code>:</p>
<pre><code class="language-plaintext">Stack:   [1, [2, [3]]]   result: []
Pop [2, [3]] → it's an array → push 2 and [3] back
Stack:   [1, 2, [3]]     result: []
Pop [3]      → it's an array → push 3 back
Stack:   [1, 2, 3]       result: []
Pop 3        → plain value  → result: [3]
Pop 2        → plain value  → result: [3, 2]
Pop 1        → plain value  → result: [3, 2, 1]
Reverse:                     result: [1, 2, 3]
</code></pre>
<p>Because we use <code>pop</code> (LIFO), values come out in reverse order — hence the <code>.reverse()</code> at the end. This approach handles arrays of any depth without ever growing the call stack.</p>
<hr />
<h2>Approach 6: <code>toString()</code> — the hacky one</h2>
<p>You will occasionally see this trick in the wild. It works only for arrays of primitive values:</p>
<pre><code class="language-js">[1, [2, [3, [4]]]].toString().split(",").map(Number);
// [1, 2, 3, 4]
</code></pre>
<p>Every element gets stringified and joined with commas, then split back apart and converted to numbers. It is clever for specific cases, but it falls apart the moment your array contains objects, <code>null</code>, or strings with commas. Do not use it in production. Know it so you can explain why it is problematic.</p>
<hr />
<h2>All Approaches at a Glance</h2>
<table>
<thead>
<tr>
<th>Approach</th>
<th>Depth</th>
<th>Notes</th>
</tr>
</thead>
<tbody><tr>
<td><code>arr.flat(n)</code></td>
<td>Any</td>
<td>Cleanest; ES2019+</td>
</tr>
<tr>
<td><code>arr.flatMap(fn)</code></td>
<td>1</td>
<td>Map + flatten in one pass</td>
</tr>
<tr>
<td><code>reduce</code> + <code>concat</code></td>
<td>1</td>
<td>Pre-ES2019 standard</td>
</tr>
<tr>
<td>Spread + <code>concat</code></td>
<td>1</td>
<td>Concise one-liner</td>
</tr>
<tr>
<td>Recursion</td>
<td>Any</td>
<td>Readable; call stack risk</td>
</tr>
<tr>
<td>Iterative (stack)</td>
<td>Any</td>
<td>Safe; best for deep arrays</td>
</tr>
<tr>
<td><code>toString</code> + <code>split</code></td>
<td>Any</td>
<td>Primitives only; fragile</td>
</tr>
</tbody></table>
<hr />
<h2>Common Interview Scenarios</h2>
<p>Interviewers test array flattening because it exercises several things at once: recursion, iteration, edge case handling, and familiarity with the standard library. Here are the scenarios you should be ready for.</p>
<hr />
<h3>Scenario 1: "Implement <code>flat()</code> without using <code>flat()</code>"</h3>
<p>This is the most common prompt. The expected answer is a recursive approach:</p>
<pre><code class="language-js">function myFlat(arr, depth = 1) {
  if (depth === 0) return arr.slice();

  return arr.reduce((acc, val) =&gt; {
    if (Array.isArray(val)) {
      return acc.concat(myFlat(val, depth - 1));
    }
    return acc.concat(val);
  }, []);
}

myFlat([1, [2, [3]]], 1);        // [1, 2, [3]]
myFlat([1, [2, [3]]], 2);        // [1, 2, 3]
myFlat([1, [2, [3]]], Infinity); // [1, 2, 3]
</code></pre>
<p>Notice how <code>depth</code> decrements on each recursive call. When it hits <code>0</code>, recursion stops and the remaining structure is returned as-is. Handling <code>Infinity</code> correctly without infinite looping works because <code>Infinity - 1 === Infinity</code> and the recursion terminates naturally when there are no more arrays to unwrap.</p>
<hr />
<h3>Scenario 2: "Flatten without recursion"</h3>
<p>The follow-up is usually: "Now do it iteratively." This tests whether you can translate a recursive algorithm into a loop.</p>
<pre><code class="language-js">function flatIterative(arr) {
  const stack = [...arr];
  const result = [];

  while (stack.length) {
    const item = stack.pop();
    if (Array.isArray(item)) {
      stack.push(...item);
    } else {
      result.push(item);
    }
  }

  return result.reverse();
}
</code></pre>
<p>Walk through it with a small example on the whiteboard. Interviewers want to see you reason about it, not just produce the answer.</p>
<hr />
<h3>Scenario 3: "Flatten and remove duplicates"</h3>
<p>A practical follow-up: after flattening, return only unique values.</p>
<pre><code class="language-js">function flatUnique(arr) {
  return [...new Set(arr.flat(Infinity))];
}

flatUnique([1, [2, 2], [3, [1, 4]]]);
// [1, 2, 3, 4]
</code></pre>
<p><code>Set</code> automatically removes duplicates. Spreading it back into an array gives you the clean result. You can also chain this manually if the interviewer wants no built-ins:</p>
<pre><code class="language-js">function flatUnique(arr) {
  const flat = arr.flat(Infinity);
  return flat.filter((val, index) =&gt; flat.indexOf(val) === index);
}
</code></pre>
<hr />
<h3>Scenario 4: "Flatten an array of objects"</h3>
<p>Flattening is not always about primitives. You might flatten an array of arrays of objects:</p>
<pre><code class="language-js">const nested = [
  [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }],
  [{ id: 3, name: "Carol" }]
];

nested.flat();
// [{ id: 1 }, { id: 2 }, { id: 3 }]
</code></pre>
<p>Or extract specific fields while flattening using <code>flatMap</code>:</p>
<pre><code class="language-js">const names = nested.flatMap(group =&gt; group.map(u =&gt; u.name));
// ["Alice", "Bob", "Carol"]
</code></pre>
<hr />
<h3>Scenario 5: "Flatten with a depth limit and count operations"</h3>
<p>Occasionally you will be asked to flatten only to a certain depth and track how many elements were processed — testing whether you understand the algorithm, not just the API.</p>
<pre><code class="language-js">function flatWithCount(arr, depth = Infinity) {
  let count = 0;

  function recurse(a, d) {
    return a.reduce((acc, val) =&gt; {
      count++;
      if (Array.isArray(val) &amp;&amp; d &gt; 0) {
        return acc.concat(recurse(val, d - 1));
      }
      return acc.concat(val);
    }, []);
  }

  return { result: recurse(arr, depth), count };
}

flatWithCount([1, [2, [3]]], 1);
// { result: [1, 2, [3]], count: 3 }
</code></pre>
<hr />
<h2>Edge Cases Worth Knowing</h2>
<p><strong>Empty arrays.</strong> Flattening an empty array returns an empty array. No special handling needed.</p>
<pre><code class="language-js">[].flat(); // []
[[],[]].flat(); // []
</code></pre>
<p><strong>Sparse arrays.</strong> <code>flat()</code> removes empty slots:</p>
<pre><code class="language-js">[1, , 3].flat(); // [1, 3]
</code></pre>
<p><strong>Mixed types.</strong> Flattening works on any mix of types — numbers, strings, objects, booleans. Values are preserved as-is.</p>
<pre><code class="language-js">[1, ["hello"], [true, null]].flat();
// [1, "hello", true, null]
</code></pre>
<p><strong>Already flat.</strong> Calling <code>flat()</code> on a flat array returns a shallow copy. It does not throw.</p>
<pre><code class="language-js">[1, 2, 3].flat(); // [1, 2, 3]  — a new array
</code></pre>
<hr />
<h2>Putting It Together: A Real-World Example</h2>
<p>Suppose you are building a tag system. Each post has an array of tags, and you fetch multiple pages of posts:</p>
<pre><code class="language-js">const pages = [
  [{ title: "Post A", tags: ["js", "web"] }, { title: "Post B", tags: ["css"] }],
  [{ title: "Post C", tags: ["js", "node"] }]
];

const allPosts = pages.flat();
const allTags = [...new Set(allPosts.flatMap(post =&gt; post.tags))];

console.log(allTags); // ["js", "web", "css", "node"]
</code></pre>
<p>Step by step:</p>
<ul>
<li><p><code>pages.flat()</code> collapses the paginated chunks into a single list of posts.</p>
</li>
<li><p><code>flatMap(post =&gt; post.tags)</code> extracts every tag from every post, flattening the resulting array of arrays.</p>
</li>
<li><p><code>new Set(...)</code> removes duplicates, and spreading it gives a clean array.</p>
</li>
</ul>
<p>Two lines of readable, declarative code to solve a genuinely common problem.</p>
<hr />
<h2>Wrapping Up</h2>
<p>Flattening arrays is a small skill with a wide reach. Once you understand the concept — removing layers of nesting to get at the values inside — you can apply it to almost any data shape you encounter.</p>
<p>Start with <code>flat()</code> and <code>flatMap()</code> for everyday use. Understand the <code>reduce</code>-based approach for compatibility. Know the recursive and iterative implementations cold if you are preparing for interviews. And always think about depth — flat by one level versus all the way down are meaningfully different operations.</p>
<p>The flattening problem looks simple on the surface, which is exactly why it shows up in interviews: the implementation reveals whether you truly understand arrays, recursion, and iteration, or whether you are just calling built-ins without knowing what is underneath.</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Modules Explained: Write Code That Actually Scales]]></title><description><![CDATA[At some point, every JavaScript developer faces the same problem. The project starts small — a few functions in a single file — and then slowly, almost invisibly, that file becomes a problem. You scro]]></description><link>https://blogs.arnabsamanta.in/javascript-modules-explained-write-code-that-actually-scales</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/javascript-modules-explained-write-code-that-actually-scales</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Sat, 28 Mar 2026 14:31:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/92e3b2e9-08b1-45a1-ae96-0d84e8c452f3.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>At some point, every JavaScript developer faces the same problem. The project starts small — a few functions in a single file — and then slowly, almost invisibly, that file becomes a problem. You scroll past hundreds of lines just to find one function. A variable you changed in one place breaks something unexpected somewhere else. Adding a teammate to the project feels risky because nobody is quite sure what touches what.</p>
<p>This is the code organization problem, and it is one of the oldest frustrations in software development. JavaScript modules exist specifically to solve it.</p>
<hr />
<h2>The Problem with One Big File</h2>
<p>Imagine building a web app where everything lives in a single <code>app.js</code>:</p>
<pre><code class="language-js">// app.js — 800 lines and growing
let currentUser = null;
let cartItems = [];

function validateEmail(email) { ... }
function hashPassword(pwd) { ... }
function addToCart(item) { ... }
function removeFromCart(id) { ... }
function fetchProducts() { ... }
function renderProductList(products) { ... }
function handleCheckout() { ... }
// ... and 50 more functions
</code></pre>
<p>This setup has real consequences:</p>
<p><strong>Name collisions.</strong> Every function and variable shares the same global scope. A <code>formatDate</code> utility you write today will conflict with a library that defines its own <code>formatDate</code> tomorrow.</p>
<p><strong>Invisible dependencies.</strong> When <code>handleCheckout</code> silently depends on <code>cartItems</code> being set by <code>addToCart</code>, nothing enforces that contract. A future refactor breaks it without warning.</p>
<p><strong>No clear ownership.</strong> When a bug appears in the cart logic, you search through authentication code, rendering code, and utility functions all tangled together.</p>
<p><strong>Testing is painful.</strong> You cannot import and test one piece in isolation because everything is coupled to everything else.</p>
<p>Modules fix all of this by letting you split your code into focused files, each responsible for one thing, with explicit contracts about what they share.</p>
<hr />
<h2>What Is a Module?</h2>
<p>A module is simply a JavaScript file that explicitly declares what it exposes to the outside world and what it depends on from other files. Nothing leaks out accidentally. Nothing gets in without being asked for.</p>
<p>Every modern JavaScript file can be treated as a module. In the browser, you signal this with <code>type="module"</code> on your script tag:</p>
<pre><code class="language-html">&lt;script type="module" src="app.js"&gt;&lt;/script&gt;
</code></pre>
<p>In Node.js, you either use the <code>.mjs</code> extension or set <code>"type": "module"</code> in your <code>package.json</code>.</p>
<hr />
<h2>Exporting: Declaring What You Share</h2>
<p>By default, everything in a module file is private. To make something available to other files, you use the <code>export</code> keyword.</p>
<h3>Named Exports</h3>
<p>You can export as many things as you want from a single file, each with its own name:</p>
<pre><code class="language-js">// utils/math.js

export function add(a, b) {
  return a + b;
}

export function multiply(a, b) {
  return a * b;
}

export const PI = 3.14159;
</code></pre>
<p>You can also export at the bottom of the file, which many developers prefer because it gives you a clear picture of the module's public surface at a glance:</p>
<pre><code class="language-js">// utils/math.js

function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }
const PI = 3.14159;

export { add, multiply, PI };
</code></pre>
<h3>Default Exports</h3>
<p>A module can also have one default export — typically used when a file is built around a single primary thing:</p>
<pre><code class="language-js">// utils/formatDate.js

export default function formatDate(date) {
  return date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'long',
    day: 'numeric',
  });
}
</code></pre>
<hr />
<h2>Importing: Declaring What You Need</h2>
<p>When a file needs something from another module, it says so explicitly at the top using <code>import</code>.</p>
<h3>Importing Named Exports</h3>
<pre><code class="language-js">// app.js
import { add, multiply, PI } from './utils/math.js';

console.log(add(2, 3));       // 5
console.log(multiply(4, PI)); // 12.56636
</code></pre>
<p>You can only import names that were exported. If <code>math.js</code> does not export <code>subtract</code>, trying to import it gives you a clear error immediately — not a silent <code>undefined</code> at runtime.</p>
<p>You can also rename imports to avoid conflicts:</p>
<pre><code class="language-js">import { add as sum } from './utils/math.js';
</code></pre>
<h3>Importing Default Exports</h3>
<p>Default exports are imported without curly braces, and you can give them any name:</p>
<pre><code class="language-js">import formatDate from './utils/formatDate.js';

console.log(formatDate(new Date())); // March 28, 2026
</code></pre>
<h3>Importing Everything</h3>
<p>If you need all exports from a module, you can import them as a namespace object:</p>
<pre><code class="language-js">import * as MathUtils from './utils/math.js';

MathUtils.add(1, 2);
MathUtils.multiply(3, 4);
</code></pre>
<hr />
<h2>Default vs Named Exports</h2>
<p>This is a common point of confusion. Here is a practical way to think about it:</p>
<table>
<thead>
<tr>
<th>Scenario</th>
<th>Use</th>
</tr>
</thead>
<tbody><tr>
<td>The file has one primary thing to export (a class, a main function)</td>
<td><code>export default</code></td>
</tr>
<tr>
<td>The file provides a collection of related utilities</td>
<td>Named exports</td>
</tr>
<tr>
<td>You want auto-import suggestions in your editor to work reliably</td>
<td>Named exports</td>
</tr>
<tr>
<td>You want consumers to import without knowing internal names</td>
<td><code>export default</code></td>
</tr>
</tbody></table>
<p>You can mix both in one file, though it is usually a sign that the file is doing too much:</p>
<pre><code class="language-js">// auth.js
export default class AuthService { ... }
export function hashPassword(pwd) { ... }  // named
export const SESSION_TIMEOUT = 3600;       // named
</code></pre>
<p>A good rule of thumb: if you find yourself writing <code>export default</code> along with five named exports in the same file, consider splitting it.</p>
<hr />
<h2>Visualizing the Dependency Flow</h2>
<p>Here is what a modular project structure looks like in practice:</p>
<pre><code class="language-plaintext">src/
├── app.js              ← entry point
├── auth/
│   ├── authService.js  ← exports AuthService (default)
│   └── validators.js   ← exports validateEmail, validatePassword
├── cart/
│   ├── cartStore.js    ← exports cartItems, addToCart, removeFromCart
│   └── cartUI.js       ← imports from cartStore.js
└── utils/
    ├── math.js         ← exports add, multiply, PI
    └── formatDate.js   ← exports default formatDate
</code></pre>
<p><code>app.js</code> imports from <code>authService.js</code> and <code>cartStore.js</code>. <code>cartUI.js</code> imports from <code>cartStore.js</code>. <code>authService.js</code> imports <code>validateEmail</code> from <code>validators.js</code>. The dependency graph is a directed tree — you can trace exactly what depends on what.</p>
<p>This structure makes a few things immediately obvious: changing <code>cartStore.js</code> affects <code>cartUI.js</code> and <code>app.js</code>, but nothing in the <code>auth/</code> folder. You can refactor with confidence.</p>
<hr />
<h2>A Real Example: Before and After</h2>
<h3>Before (single file chaos)</h3>
<pre><code class="language-js">// app.js
let cart = [];

function addToCart(item) { cart.push(item); renderCart(); }
function removeFromCart(id) { cart = cart.filter(i =&gt; i.id !== id); renderCart(); }
function renderCart() { /* DOM manipulation */ }
function validateEmail(email) { return /\S+@\S+\.\S+/.test(email); }
function handleLogin(email, password) { if (validateEmail(email)) { /* login */ } }
</code></pre>
<h3>After (modular)</h3>
<pre><code class="language-js">// cart/cartStore.js
let cart = [];
export function addToCart(item) { cart.push(item); }
export function removeFromCart(id) { cart = cart.filter(i =&gt; i.id !== id); }
export function getCart() { return [...cart]; }
</code></pre>
<pre><code class="language-js">// cart/cartUI.js
import { getCart, addToCart, removeFromCart } from './cartStore.js';

export function renderCart() {
  const items = getCart();
  // DOM manipulation using items
}
</code></pre>
<pre><code class="language-js">// auth/validators.js
export function validateEmail(email) {
  return /\S+@\S+\.\S+/.test(email);
}
</code></pre>
<pre><code class="language-js">// auth/authService.js
import { validateEmail } from './validators.js';

export default function handleLogin(email, password) {
  if (!validateEmail(email)) throw new Error('Invalid email');
  // login logic
}
</code></pre>
<pre><code class="language-js">// app.js
import handleLogin from './auth/authService.js';
import { renderCart } from './cart/cartUI.js';
import { addToCart } from './cart/cartStore.js';

// Only connects the pieces — no logic lives here directly
</code></pre>
<p>The entry point becomes a thin orchestration layer. Each piece of logic lives in a file named exactly after what it does.</p>
<hr />
<h2>Why Modular Code Is Better to Work With</h2>
<h3>Maintainability</h3>
<p>When you need to fix a bug in the cart logic, you open <code>cartStore.js</code>. You do not sift through authentication code or rendering utilities. The file is small and focused, and the fix is contained.</p>
<h3>Reusability</h3>
<p><code>validateEmail</code> in <code>validators.js</code> can be imported by the registration page, the login page, and the settings page. You write it once and trust it everywhere. If the regex ever needs updating, there is exactly one place to change it.</p>
<h3>Testability</h3>
<pre><code class="language-js">// cartStore.test.js
import { addToCart, getCart } from './cart/cartStore.js';

test('addToCart appends an item', () =&gt; {
  addToCart({ id: 1, name: 'Keyboard' });
  expect(getCart()).toHaveLength(1);
});
</code></pre>
<p>You import just the module you want to test. No globals to reset, no side effects leaking in from unrelated code.</p>
<h3>Team Collaboration</h3>
<p>When modules have clear, named exports, merge conflicts become rare. Two developers working on <code>cartStore.js</code> and <code>authService.js</code> respectively are working on truly separate files. Their changes do not touch each other.</p>
<h3>Encapsulation</h3>
<p>Private implementation details stay private. In <code>cartStore.js</code>, the raw <code>cart</code> array is never exported — consumers can only interact with it through <code>addToCart</code>, <code>removeFromCart</code>, and <code>getCart</code>. If you later change the internal data structure from an array to a <code>Map</code>, nothing outside the file needs to change.</p>
<hr />
<h2>Common Mistakes to Avoid</h2>
<p><strong>Circular imports.</strong> If <code>a.js</code> imports from <code>b.js</code> and <code>b.js</code> imports from <code>a.js</code>, you have a circular dependency. JavaScript handles this without throwing an error, but the values may be <code>undefined</code> at the time they are used. The fix is usually to extract the shared piece into a third file that both can import from.</p>
<p><strong>Treating default exports as a convention for everything.</strong> Default exports make refactoring harder because different files can import the same thing under different names. For utility modules especially, named exports give you better editor tooling and make global renames safer.</p>
<p><strong>Forgetting</strong> <code>.js</code> <strong>extensions in browser environments.</strong> Unlike Node.js with bundlers, the browser's native module loader requires explicit file extensions in import paths:</p>
<pre><code class="language-js">// This works in the browser
import { add } from './utils/math.js';

// This does not (without a bundler)
import { add } from './utils/math';
</code></pre>
<hr />
<h2>What About Bundlers?</h2>
<p>Tools like Vite, webpack, and esbuild take all your modules and combine them into optimized files for production. They handle things like tree shaking (removing code you imported but never used), code splitting (loading modules on demand), and compatibility with older browsers.</p>
<p>But bundlers are a layer on top of modules, not a replacement for them. You write the same <code>import</code> and <code>export</code> syntax either way. Understanding modules first means you understand what the bundler is doing for you.</p>
<hr />
<h2>Wrapping Up</h2>
<p>JavaScript modules solve a genuinely hard problem — how do you write code that stays understandable and maintainable as it grows? The answer is explicit contracts: you declare what a file shares, you declare what a file needs, and the runtime enforces it.</p>
<p>The shift from thinking in functions scattered across a global scope to thinking in focused, composable modules is one of the more durable improvements you can make to how you write JavaScript. Files become smaller and easier to reason about. Dependencies become visible. Testing becomes straightforward.</p>
<p>Start with one module. Move one related group of functions into its own file, export them, and import them where you need them. The habit builds from there.</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Operators: Working with Values]]></title><description><![CDATA[Every useful program does something with data — adds numbers, compares values, checks conditions. Operators are the symbols that make all of that happen. You have already used them without thinking mu]]></description><link>https://blogs.arnabsamanta.in/javascript-operators-working-with-values</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/javascript-operators-working-with-values</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Fri, 13 Mar 2026 07:40:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/08084020-f2a2-460f-9a5d-db46455f30ff.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every useful program does something with data — adds numbers, compares values, checks conditions. Operators are the symbols that make all of that happen. You have already used them without thinking much about it: <code>=</code> to assign a value, <code>+</code> to add numbers, <code>!</code> to flip a boolean.</p>
<p>This article walks through the four categories of operators you will use constantly, with clear examples for each.</p>
<hr />
<h2>What is an Operator?</h2>
<p>An operator is a symbol that performs an operation on one or more values. The values it works on are called <strong>operands</strong>.</p>
<pre><code class="language-js">let result = 10 + 5;
//           ─┬─ ─ ─┬─
//            │     │
//         operand  operand
//              ─┬─
//            operator
</code></pre>
<p>JavaScript groups operators by what they do. There are four categories covered in this article:</p>
<pre><code class="language-plaintext">┌──────────────────────────────────────────────────────────┐
│                  Operator Categories                     │
├──────────────────┬───────────────────────────────────────┤
│  Arithmetic      │  +   -   *   /   %                    │
│  Comparison      │  ==  ===  !=  !==  &gt;  &lt;  &gt;=  &lt;=       │
│  Logical         │  &amp;&amp;  ||   !                           │
│  Assignment      │  =   +=  -=  *=  /=                   │
└──────────────────┴───────────────────────────────────────┘
</code></pre>
<hr />
<h2>Arithmetic Operators</h2>
<p>Arithmetic operators perform math on numbers. They work exactly as you would expect from school.</p>
<pre><code class="language-js">let a = 20;
let b = 6;

console.log(a + b);  // 26  — addition
console.log(a - b);  // 14  — subtraction
console.log(a * b);  // 120 — multiplication
console.log(a / b);  // 3.3333... — division
console.log(a % b);  // 2   — remainder (modulus)
</code></pre>
<p>The modulus operator <code>%</code> is the one most beginners find unfamiliar. It gives you the <strong>remainder</strong> after dividing two numbers — not the result of the division itself.</p>
<pre><code class="language-js">console.log(10 % 3); // 1  — because 10 = 3×3 + 1
console.log(15 % 5); // 0  — because 15 = 5×3 + 0 (divides evenly)
console.log(7 % 2);  // 1  — because 7 = 2×3 + 1
</code></pre>
<p>A practical use for <code>%</code> is checking whether a number is even or odd:</p>
<pre><code class="language-js">let num = 14;

if (num % 2 === 0) {
  console.log(num + " is even");
} else {
  console.log(num + " is odd");
}
// 14 is even
</code></pre>
<h3>Arithmetic with strings</h3>
<p>The <code>+</code> operator has a special behavior when used with strings — it concatenates them instead of adding:</p>
<pre><code class="language-js">console.log("Hello" + " " + "World"); // "Hello World"
console.log("Score: " + 100);         // "Score: 100"
</code></pre>
<p>If one side is a string and the other is a number, JavaScript converts the number to a string and joins them. This can cause surprises:</p>
<pre><code class="language-js">console.log("5" + 3);  // "53" — not 8! String concatenation wins
console.log("5" - 3);  // 2   — minus has no string behavior, so JS converts "5" to a number
</code></pre>
<p>The <code>+</code> operator is the only arithmetic operator with this string behavior. All others (<code>-</code>, <code>*</code>, <code>/</code>, <code>%</code>) will try to convert strings to numbers first.</p>
<h3>Increment and decrement</h3>
<p>Two shorthand operators for adding or subtracting 1:</p>
<pre><code class="language-js">let count = 0;

count++; // same as count = count + 1
console.log(count); // 1

count++:
console.log(count); // 2

count--; // same as count = count - 1
console.log(count); // 1
</code></pre>
<hr />
<h2>Comparison Operators</h2>
<p>Comparison operators compare two values and always return a <strong>boolean</strong> — either <code>true</code> or <code>false</code>.</p>
<pre><code class="language-js">let x = 10;
let y = 20;

console.log(x &gt; y);  // false — is 10 greater than 20?
console.log(x &lt; y);  // true  — is 10 less than 20?
console.log(x &gt;= 10); // true — is 10 greater than or equal to 10?
console.log(x &lt;= 9);  // false — is 10 less than or equal to 9?
</code></pre>
<h3><code>==</code> vs <code>===</code> — The most important distinction</h3>
<p>This is the comparison operators pair that trips up nearly every beginner, and it is worth understanding clearly.</p>
<p><code>==</code> <strong>(loose equality)</strong> — compares values after converting both sides to the same type. It is lenient.</p>
<p><code>===</code> <strong>(strict equality)</strong> — compares both value AND type. No conversion happens.</p>
<pre><code class="language-js">console.log(5 == "5");   // true  — "5" is converted to 5, then compared
console.log(5 === "5");  // false — number vs string, types differ

console.log(0 == false);  // true  — false converts to 0
console.log(0 === false); // false — number vs boolean

console.log(null == undefined);  // true  — special case in JS
console.log(null === undefined); // false — different types

console.log(1 == true);   // true  — true converts to 1
console.log(1 === true);  // false — number vs boolean
</code></pre>
<p>The type conversion <code>==</code> performs can produce results that seem wrong. In almost every situation you should use <code>===</code>. It says exactly what you mean: "are these two values the same value of the same type?"</p>
<pre><code class="language-js">// A common bug caused by ==
let userInput = "42"; // came from a text field — it's a string
let expectedValue = 42; // a number

if (userInput == expectedValue) {
  console.log("Match!"); // prints Match! — might not be what you wanted
}

if (userInput === expectedValue) {
  console.log("Exact match!"); // does NOT print — types differ
}
</code></pre>
<h3><code>!=</code> and <code>!==</code></h3>
<p>The inequality counterparts follow the same rule:</p>
<pre><code class="language-js">console.log(5 != "5");   // false — after conversion they are equal
console.log(5 !== "5");  // true  — different types, so not strictly equal

console.log(10 != 20);   // true  — they are not equal
console.log(10 !== 20);  // true  — neither value nor type match
</code></pre>
<p>As with equality, prefer <code>!==</code> over <code>!=</code> in your code.</p>
<hr />
<h2>Logical Operators</h2>
<p>Logical operators work with boolean values and let you combine or invert conditions. They are the building blocks of decision-making in code.</p>
<h3><code>&amp;&amp;</code> — AND</h3>
<p>Returns <code>true</code> only when <strong>both</strong> sides are <code>true</code>. If either side is <code>false</code>, the result is <code>false</code>.</p>
<pre><code class="language-js">console.log(true &amp;&amp; true);   // true
console.log(true &amp;&amp; false);  // false
console.log(false &amp;&amp; true);  // false
console.log(false &amp;&amp; false); // false
</code></pre>
<p>Practical use — checking multiple conditions at once:</p>
<pre><code class="language-js">let age = 20;
let hasID = true;

if (age &gt;= 18 &amp;&amp; hasID) {
  console.log("Entry allowed.");
} else {
  console.log("Entry denied.");
}
// Entry allowed.

let isLoggedIn = true;
let isAdmin = false;

if (isLoggedIn &amp;&amp; isAdmin) {
  console.log("Welcome to the admin panel.");
} else {
  console.log("Access denied.");
}
// Access denied. — isAdmin is false, so &amp;&amp; fails
</code></pre>
<h3><code>||</code> — OR</h3>
<p>Returns <code>true</code> when <strong>at least one</strong> side is <code>true</code>. Only returns <code>false</code> when both sides are <code>false</code>.</p>
<pre><code class="language-js">console.log(true || true);   // true
console.log(true || false);  // true
console.log(false || true);  // true
console.log(false || false); // false
</code></pre>
<p>Practical use — checking if at least one condition is met:</p>
<pre><code class="language-js">let isWeekend = false;
let isHoliday = true;

if (isWeekend || isHoliday) {
  console.log("No work today!");
} else {
  console.log("Back to work.");
}
// No work today! — isHoliday is true, so || passes

let hasCash = false;
let hasCard = false;

if (hasCash || hasCard) {
  console.log("Purchase successful.");
} else {
  console.log("No payment method available.");
}
// No payment method available. — both are false
</code></pre>
<h3><code>!</code> — NOT</h3>
<p>Flips a boolean. <code>true</code> becomes <code>false</code>, <code>false</code> becomes <code>true</code>.</p>
<pre><code class="language-js">console.log(!true);  // false
console.log(!false); // true

let isLoggedIn = false;
console.log(!isLoggedIn); // true — the user is NOT logged in

// Common pattern: toggle a value
let darkMode = false;
darkMode = !darkMode;
console.log(darkMode); // true

darkMode = !darkMode;
console.log(darkMode); // false
</code></pre>
<h3>Truth table</h3>
<pre><code class="language-plaintext">┌─────────┬─────────┬──────────┬──────────┬──────────┐
│    A    │    B    │  A &amp;&amp; B  │  A || B  │    !A    │
├─────────┼─────────┼──────────┼──────────┼──────────┤
│  true   │  true   │   true   │   true   │  false   │
│  true   │  false  │   false  │   true   │  false   │
│  false  │  true   │   false  │   true   │   true   │
│  false  │  false  │   false  │   false  │   true   │
└─────────┴─────────┴──────────┴──────────┴──────────┘
</code></pre>
<hr />
<h2>Assignment Operators</h2>
<p>You already know <code>=</code> — it assigns a value to a variable. The other assignment operators are shorthands that combine a math operation with assignment.</p>
<pre><code class="language-js">let score = 100;

score += 10; // same as: score = score + 10
console.log(score); // 110

score -= 20; // same as: score = score - 20
console.log(score); // 90

score *= 2;  // same as: score = score * 2
console.log(score); // 180

score /= 3;  // same as: score = score / 3
console.log(score); // 60

score %= 7;  // same as: score = score % 7
console.log(score); // 4
</code></pre>
<p>These are purely shorthand — they do not do anything you could not do with <code>score = score + 10</code>. They just make the code shorter and easier to read, especially in loops:</p>
<pre><code class="language-js">let total = 0;
let prices = [120, 85, 200, 45, 310];

for (let i = 0; i &lt; prices.length; i++) {
  total += prices[i]; // accumulate without writing total = total + prices[i] each time
}

console.log("Total:", total); // Total: 760
</code></pre>
<hr />
<h2>Putting It All Together</h2>
<p>Here is a small program that uses all four categories together — arithmetic to calculate, comparison to evaluate, logical to combine conditions, and assignment to track state:</p>
<pre><code class="language-js">let num1 = 15;
let num2 = 4;

// Arithmetic
console.log("Sum:", num1 + num2);       // 19
console.log("Difference:", num1 - num2); // 11
console.log("Product:", num1 * num2);    // 60
console.log("Quotient:", num1 / num2);   // 3.75
console.log("Remainder:", num1 % num2);  // 3

// Comparison
console.log(num1 &gt; num2);    // true
console.log(num1 === 15);    // true
console.log(num1 === "15");  // false — strict equality catches the type difference
console.log(num1 == "15");   // true  — loose equality converts the string

// Logical
let isPositive = num1 &gt; 0;   // true
let isEven = num1 % 2 === 0; // false — 15 is odd

console.log("Positive AND even:", isPositive &amp;&amp; isEven); // false
console.log("Positive OR even:", isPositive || isEven);  // true
console.log("Not positive:", !isPositive);               // false

// Assignment operators
let total = 0;
total += num1; // 15
total += num2; // 19
total *= 2;    // 38
console.log("Total after operations:", total); // 38
</code></pre>
<hr />
<h2>Quick Recap</h2>
<ul>
<li><p><strong>Arithmetic operators</strong> perform math: <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>%</code>. The <code>%</code> gives the remainder after division.</p>
</li>
<li><p><strong>Comparison operators</strong> return <code>true</code> or <code>false</code>. Always prefer <code>===</code> over <code>==</code> — it checks type as well as value.</p>
</li>
<li><p><strong>Logical operators</strong> combine or invert boolean values: <code>&amp;&amp;</code> (both must be true), <code>||</code> (at least one must be true), <code>!</code> (flips the value).</p>
</li>
<li><p><strong>Assignment operators</strong> are shorthands: <code>+=</code>, <code>-=</code>, <code>*=</code>, <code>/=</code>, <code>%=</code> update a variable in place.</p>
</li>
</ul>
<hr />
]]></content:encoded></item><item><title><![CDATA[JavaScript this, call(), apply(), and bind() Explained]]></title><description><![CDATA[If you have spent any time reading JavaScript code, you have seen this pop up in unexpected places and wondered what it actually refers to. And then you stumble across call(), apply(), or bind() and t]]></description><link>https://blogs.arnabsamanta.in/javascript-this-call-apply-and-bind-explained</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/javascript-this-call-apply-and-bind-explained</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Fri, 13 Mar 2026 07:36:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/9fc809cf-6286-4c2f-97c3-951287b1ddef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have spent any time reading JavaScript code, you have seen <code>this</code> pop up in unexpected places and wondered what it actually refers to. And then you stumble across <code>call()</code>, <code>apply()</code>, or <code>bind()</code> and the confusion compounds.</p>
<p>This article breaks all of it down — <code>this</code> first, then the three methods that let you control it.</p>
<hr />
<h2>What is <code>this</code>?</h2>
<p>The simplest way to think about <code>this</code> is: <code>this</code> <strong>refers to whoever is calling the function right now</strong>.</p>
<p>It is not fixed when you write the function. It is decided at the moment the function is <em>called</em>, based on what is to the left of the dot.</p>
<pre><code class="language-js">function greet() {
  console.log("Hello, I am " + this.name);
}
</code></pre>
<p>This function uses <code>this.name</code>. But whose <code>name</code>? That depends entirely on how and where <code>greet</code> is called. The function itself does not know yet — it finds out at call time.</p>
<hr />
<h2><code>this</code> in the Global Context</h2>
<p>When you call a function on its own, with nothing to the left of the dot, <code>this</code> refers to the global object. In a browser that is <code>window</code>. In Node.js it is <code>global</code>.</p>
<pre><code class="language-js">function showThis() {
  console.log(this);
}

showThis(); // global object (window in browser, global in Node.js)
</code></pre>
<p>In strict mode, <code>this</code> is <code>undefined</code> instead of the global object, which is one reason strict mode exists — it prevents accidental writes to global variables.</p>
<pre><code class="language-js">"use strict";

function showThis() {
  console.log(this); // undefined
}

showThis();
</code></pre>
<hr />
<h2><code>this</code> Inside an Object</h2>
<p>When a function is called as a method on an object — meaning there is an object to the left of the dot — <code>this</code> refers to that object.</p>
<pre><code class="language-js">const person = {
  name: "Arjun",
  age: 21,
  greet() {
    console.log("Hi, I am " + this.name + " and I am " + this.age + " years old.");
  },
};

person.greet(); // Hi, I am Arjun and I am 21 years old.
</code></pre>
<p><code>person</code> is to the left of the dot when <code>greet()</code> is called, so <code>this</code> inside <code>greet</code> is <code>person</code>. That means <code>this.name</code> is <code>"Arjun"</code> and <code>this.age</code> is <code>21</code>.</p>
<p>Change the caller, and <code>this</code> changes with it:</p>
<pre><code class="language-js">const person1 = {
  name: "Arjun",
  greet() {
    console.log("Hi, I am " + this.name);
  },
};

const person2 = {
  name: "Priya",
};

// person2 borrows person1's greet method
person2.greet = person1.greet;

person1.greet(); // Hi, I am Arjun  — this = person1
person2.greet(); // Hi, I am Priya  — this = person2
</code></pre>
<p>The exact same function, called on two different objects, produces two different results because <code>this</code> takes the value of whatever object is doing the calling.</p>
<hr />
<h2>The Caller Relationship</h2>
<pre><code class="language-plaintext">  object.method()
  ───────┬───────
         │
         ▼
  "this" inside method = that object

  ┌──────────────┐        ┌─────────────────────────┐
  │   person1    │──────► │  greet()                │
  │  name:"Arjun"│  calls │  this.name → "Arjun"    │
  └──────────────┘        └─────────────────────────┘

  ┌──────────────┐        ┌─────────────────────────┐
  │   person2    │──────► │  greet()  (same fn)     │
  │  name:"Priya"│  calls │  this.name → "Priya"    │
  └──────────────┘        └─────────────────────────┘
</code></pre>
<hr />
<h2>Losing <code>this</code></h2>
<p>A common source of bugs is when a method is pulled out of its object and called on its own. The object context is lost.</p>
<pre><code class="language-js">const person = {
  name: "Arjun",
  greet() {
    console.log("Hi, I am " + this.name);
  },
};

person.greet(); // Hi, I am Arjun — works fine

// Storing the method in a variable loses the object context
const fn = person.greet;
fn(); // Hi, I am undefined — this is now global, which has no 'name'
</code></pre>
<p>This is the exact problem that <code>call</code>, <code>apply</code>, and <code>bind</code> are designed to solve. They let you explicitly tell a function what <code>this</code> should be when it runs.</p>
<hr />
<h2><code>call()</code></h2>
<p><code>call()</code> lets you invoke a function immediately and specify what <code>this</code> should be. Any arguments you want to pass to the function go after the first argument.</p>
<pre><code class="language-js">function introduce(city, hobby) {
  console.log(`I am \({this.name}, from \){city}. I like ${hobby}.`);
}

const person1 = { name: "Arjun" };
const person2 = { name: "Priya" };

// Call introduce with person1 as 'this'
introduce.call(person1, "Mumbai", "coding");
// I am Arjun, from Mumbai. I like coding.

// Call the same function with person2 as 'this'
introduce.call(person2, "Delhi", "reading");
// I am Priya, from Delhi. I like reading.
</code></pre>
<p>The function <code>introduce</code> was never on either object. <code>call()</code> borrowed it and ran it as if it were, with the specified object as <code>this</code>.</p>
<p>A practical case — borrowing a method from one object to use on another:</p>
<pre><code class="language-js">const employee = {
  name: "Arjun",
  department: "Engineering",
  describe() {
    console.log(`\({this.name} works in \){this.department}.`);
  },
};

const contractor = {
  name: "Rohan",
  department: "Design",
};

// contractor doesn't have describe() — borrow it from employee
employee.describe.call(contractor);
// Rohan works in Design.
</code></pre>
<hr />
<h2><code>apply()</code></h2>
<p><code>apply()</code> does the same thing as <code>call()</code> — it invokes a function immediately with a specified <code>this</code>. The only difference is how you pass arguments: instead of a comma-separated list, you pass an <strong>array</strong>.</p>
<pre><code class="language-js">function introduce(city, hobby) {
  console.log(`I am \({this.name}, from \){city}. I like ${hobby}.`);
}

const person1 = { name: "Arjun" };
const person2 = { name: "Priya" };

// call() — arguments one by one
introduce.call(person1, "Mumbai", "coding");

// apply() — arguments as an array
introduce.apply(person1, ["Mumbai", "coding"]);

// Both produce the same output:
// I am Arjun, from Mumbai. I like coding.
</code></pre>
<p>Where <code>apply()</code> becomes genuinely useful is when you already have your arguments collected in an array:</p>
<pre><code class="language-js">function sum(a, b, c) {
  console.log(`\({this.label}: \){a + b + c}`);
}

const context = { label: "Total" };
const numbers = [10, 20, 30];

// Spread the array as individual arguments
sum.apply(context, numbers);
// Total: 60
</code></pre>
<p>Another classic use — finding the max value in an array using <code>Math.max</code>, which does not accept an array directly:</p>
<pre><code class="language-js">const scores = [88, 92, 75, 96, 61];

const max = Math.max.apply(null, scores);
console.log("Highest score:", max); // Highest score: 96
</code></pre>
<p>(<code>null</code> is passed as <code>this</code> because <code>Math.max</code> does not use <code>this</code> at all — we just need the array-spreading behavior.)</p>
<hr />
<h2><code>bind()</code></h2>
<p><code>bind()</code> is different from <code>call()</code> and <code>apply()</code> in one important way: <strong>it does not call the function immediately</strong>. Instead it returns a new function with <code>this</code> permanently fixed to whatever you specify. You call that new function whenever you need it.</p>
<pre><code class="language-js">function greet(greeting) {
  console.log(`\({greeting}, I am \){this.name}.`);
}

const person = { name: "Arjun" };

// bind() returns a new function — does NOT call it yet
const greetArjun = greet.bind(person);

// Call it later, whenever needed
greetArjun("Hello");   // Hello, I am Arjun.
greetArjun("Good day"); // Good day, I am Arjun.
</code></pre>
<p>No matter how many times you call <code>greetArjun</code>, or where you call it from, <code>this</code> will always be <code>person</code>. It is permanently bound.</p>
<p>This is particularly useful when passing methods as callbacks, where the object context would otherwise be lost:</p>
<pre><code class="language-js">const timer = {
  name: "Countdown",
  start() {
    console.log(this.name + " started.");
  },
};

// Without bind — 'this' is lost when the method is passed as a callback
setTimeout(timer.start, 1000); // undefined started.

// With bind — 'this' is locked to timer
setTimeout(timer.start.bind(timer), 1000); // Countdown started.
</code></pre>
<p>You can also pre-fill arguments with <code>bind()</code> — a technique called partial application:</p>
<pre><code class="language-js">function multiply(a, b) {
  return a * b;
}

// Create a new function with 'a' pre-set to 2
const double = multiply.bind(null, 2);

console.log(double(5));  // 10
console.log(double(8));  // 16
console.log(double(12)); // 24
</code></pre>
<hr />
<h2>Comparison Table</h2>
<table>
<thead>
<tr>
<th></th>
<th><code>call()</code></th>
<th><code>apply()</code></th>
<th><code>bind()</code></th>
</tr>
</thead>
<tbody><tr>
<td>Calls function immediately?</td>
<td>Yes</td>
<td>Yes</td>
<td>No — returns a new function</td>
</tr>
<tr>
<td>How arguments are passed</td>
<td>One by one: <code>fn.call(obj, a, b)</code></td>
<td>As an array: <code>fn.apply(obj, [a, b])</code></td>
<td>One by one: <code>fn.bind(obj, a, b)</code></td>
</tr>
<tr>
<td>Returns</td>
<td>The function's return value</td>
<td>The function's return value</td>
<td>A new bound function</td>
</tr>
<tr>
<td>When to use</td>
<td>Borrow a method, run it now</td>
<td>Same as call, but you have an array</td>
<td>Fix <code>this</code> for later use / callbacks</td>
</tr>
</tbody></table>
<hr />
<h2>Bringing It All Together</h2>
<p>Here is one complete example showing all three in action:</p>
<pre><code class="language-js">// A standalone function that uses 'this'
function displayProfile(city, hobby) {
  console.log(
    `Name: \({this.name} | Age: \){this.age} | City: \({city} | Hobby: \){hobby}`
  );
}

const user1 = { name: "Arjun", age: 21 };
const user2 = { name: "Priya", age: 24 };
const user3 = { name: "Rohan", age: 19 };

// call() — run immediately, arguments one by one
displayProfile.call(user1, "Mumbai", "coding");
// Name: Arjun | Age: 21 | City: Mumbai | Hobby: coding

// apply() — run immediately, arguments as array
const user2Args = ["Delhi", "painting"];
displayProfile.apply(user2, user2Args);
// Name: Priya | Age: 24 | City: Delhi | Hobby: painting

// bind() — create a reusable function locked to user3
const showRohan = displayProfile.bind(user3, "Bangalore");
showRohan("chess");   // Name: Rohan | Age: 19 | City: Bangalore | Hobby: chess
showRohan("cycling"); // Name: Rohan | Age: 19 | City: Bangalore | Hobby: cycling
</code></pre>
<hr />
<h2>Trying It All Together — Practical Demo</h2>
<p>Let's build a small realistic scenario: a <code>gradeReport</code> function that needs to work for different students.</p>
<pre><code class="language-js">function gradeReport(subject1, subject2, subject3) {
  const total = subject1 + subject2 + subject3;
  const average = (total / 3).toFixed(1);
  console.log(`\({this.name} (\){this.course}): \({subject1}, \){subject2}, \({subject3} → Avg: \){average}`);
}

const studentA = { name: "Arjun", course: "Computer Science" };
const studentB = { name: "Priya", course: "Mathematics" };
const studentC = { name: "Rohan", course: "Physics" };

// call() — run the report for studentA right now
gradeReport.call(studentA, 88, 92, 79);
// Arjun (Computer Science): 88, 92, 79 → Avg: 86.3

// apply() — Priya's scores already in an array
const priyaScores = [91, 85, 94];
gradeReport.apply(studentB, priyaScores);
// Priya (Mathematics): 91, 85, 94 → Avg: 90.0

// bind() — create a dedicated report function for Rohan
const rohanReport = gradeReport.bind(studentC);
rohanReport(76, 88, 82);
// Rohan (Physics): 76, 88, 82 → Avg: 82.0

// Later in the code, same bound function still works
rohanReport(90, 95, 88);
// Rohan (Physics): 90, 95, 88 → Avg: 91.0
</code></pre>
<hr />
<h2>Quick Recap</h2>
<ul>
<li><p><code>this</code> refers to the object that is calling the function — it is determined at call time, not at write time</p>
</li>
<li><p>Inside an object method, <code>this</code> is the object to the left of the dot</p>
</li>
<li><p>A method pulled out of its object and called standalone loses its <code>this</code> context</p>
</li>
<li><p><code>call(obj, arg1, arg2)</code> — calls the function immediately with <code>obj</code> as <code>this</code>, arguments passed one by one</p>
</li>
<li><p><code>apply(obj, [arg1, arg2])</code> — same as <code>call</code> but arguments are passed as an array</p>
</li>
<li><p><code>bind(obj, arg1)</code> — does not call the function, returns a new function with <code>this</code> permanently fixed</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming in JavaScript: Classes and Objects]]></title><description><![CDATA[Every JavaScript developer reaches a point where plain functions and objects start feeling messy. You have ten users in your app and you are creating each one manually, copy-pasting the same structure]]></description><link>https://blogs.arnabsamanta.in/object-oriented-programming-in-javascript-classes-and-objects</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/object-oriented-programming-in-javascript-classes-and-objects</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Fri, 13 Mar 2026 07:27:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/63100be2-4b45-4b58-a0d8-725b8afa1b84.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every JavaScript developer reaches a point where plain functions and objects start feeling messy. You have ten users in your app and you are creating each one manually, copy-pasting the same structure, hoping you do not forget a property. There has to be a better way.</p>
<p>That better way is Object-Oriented Programming — OOP. It is a way of organizing your code around real-world things rather than just a list of instructions.</p>
<hr />
<h2>What is OOP?</h2>
<p>OOP is a programming style where you model your program around <strong>objects</strong> — things that have both data (properties) and behavior (methods).</p>
<p>Instead of writing a function to greet a user and a separate function to update their age and another function to display their profile — all floating around independently — OOP bundles all of that together into one unit that represents a user.</p>
<p>The core idea is that your code should mirror the way you think about the real world. A car has a color and a speed. It can accelerate and brake. A student has a name and an age. They can introduce themselves and submit an assignment. OOP lets you express these ideas directly in code.</p>
<hr />
<h2>The Blueprint Analogy</h2>
<p>The single most useful way to understand OOP is the <strong>blueprint analogy</strong>.</p>
<p>An architect draws one blueprint for a house. That blueprint is not a house you can live in — it is just a plan. But from that one blueprint, you can build many actual houses. House A is blue with three bedrooms. House B is red with two bedrooms. They were both built from the same blueprint, but they are separate, independent houses.</p>
<pre><code class="language-plaintext">         BLUEPRINT (Class)
        ┌──────────────────┐
        │   House          │
        │ ─────────────    │
        │ color            │
        │ bedrooms         │
        │ ─────────────    │
        │ describe()       │
        └────────┬─────────┘
                 │
        builds many objects
        │                  │
        ▼                  ▼
┌──────────────┐   ┌──────────────┐
│  houseA      │   │  houseB      │
│ ──────────── │   │ ──────────── │
│ color:"blue" │   │ color:"red"  │
│ bedrooms: 3  │   │ bedrooms: 2  │
└──────────────┘   └──────────────┘
  (an instance)       (an instance)
</code></pre>
<p>In JavaScript:</p>
<ul>
<li><p>The <strong>blueprint</strong> is a <strong>class</strong></p>
</li>
<li><p>The actual houses built from it are <strong>objects</strong> (also called <strong>instances</strong>)</p>
</li>
<li><p>Building a house from the blueprint is called <strong>instantiation</strong></p>
</li>
</ul>
<hr />
<h2>Your First Class</h2>
<p>In JavaScript, you define a class using the <code>class</code> keyword followed by a name. By convention, class names start with a capital letter.</p>
<pre><code class="language-js">class Car {
  // class body goes here
}
</code></pre>
<p>This defines the blueprint. It does not create any car yet — it just describes what a car will look like when one is created.</p>
<p>To create an actual car from this blueprint, you use the <code>new</code> keyword:</p>
<pre><code class="language-js">class Car {
  // empty for now
}

let myCar = new Car();
let yourCar = new Car();

console.log(myCar);   // Car {}
console.log(yourCar); // Car {}
</code></pre>
<p>Both <code>myCar</code> and <code>yourCar</code> are separate objects created from the same <code>Car</code> class — just like two houses built from the same blueprint.</p>
<hr />
<h2>The Constructor Method</h2>
<p>Right now the <code>Car</code> class creates empty objects. To give each car its own data when it is created, you use the <strong>constructor</strong> — a special method that runs automatically every time you create a new instance with <code>new</code>.</p>
<pre><code class="language-js">class Car {
  constructor(brand, color, speed) {
    this.brand = brand;
    this.color = color;
    this.speed = speed;
  }
}

let car1 = new Car("Toyota", "red", 180);
let car2 = new Car("Honda", "blue", 200);

console.log(car1.brand); // "Toyota"
console.log(car1.color); // "red"
console.log(car1.speed); // 180

console.log(car2.brand); // "Honda"
console.log(car2.color); // "blue"
console.log(car2.speed); // 200
</code></pre>
<p>The <code>this</code> keyword refers to the specific object being created. When you write <code>this.brand = brand</code>, you are saying: "on <em>this particular</em> car being built right now, store the brand value."</p>
<p>Each object gets its own copy of the data. Changing <code>car1</code> does not affect <code>car2</code>.</p>
<pre><code class="language-js">car1.color = "green";

console.log(car1.color); // "green"
console.log(car2.color); // "blue" — completely unaffected
</code></pre>
<hr />
<h2>Adding Methods</h2>
<p>Methods are functions that belong to a class. They define what an object can <em>do</em>. You define them inside the class body, outside the constructor.</p>
<pre><code class="language-js">class Car {
  constructor(brand, color, speed) {
    this.brand = brand;
    this.color = color;
    this.speed = speed;
  }

  // A method — describes the car
  describe() {
    console.log(`\({this.brand} (\){this.color}) — top speed: ${this.speed} km/h`);
  }

  // A method — simulates accelerating
  accelerate(amount) {
    this.speed += amount;
    console.log(`\({this.brand} sped up! New speed: \){this.speed} km/h`);
  }
}

let car1 = new Car("Toyota", "red", 180);
let car2 = new Car("Honda", "blue", 200);

car1.describe();     // Toyota (red) — top speed: 180 km/h
car2.describe();     // Honda (blue) — top speed: 200 km/h

car1.accelerate(20); // Toyota sped up! New speed: 200 km/h
car1.describe();     // Toyota (red) — top speed: 200 km/h
car2.describe();     // Honda (blue) — top speed: 200 km/h — unchanged
</code></pre>
<p>Every object created from the <code>Car</code> class automatically gets access to <code>describe()</code> and <code>accelerate()</code>. You write the method once in the class and every instance can use it — that is reusability.</p>
<hr />
<h2>A Complete Example: Person</h2>
<p>Let's build a slightly more practical example — a <code>Person</code> class:</p>
<pre><code class="language-js">class Person {
  constructor(name, age, city) {
    this.name = name;
    this.age = age;
    this.city = city;
  }

  greet() {
    console.log(`Hi, I am \({this.name} from \){this.city}.`);
  }

  birthday() {
    this.age += 1;
    console.log(`Happy birthday \({this.name}! You are now \){this.age}.`);
  }

  introduce() {
    console.log(`Name: \({this.name} | Age: \){this.age} | City: ${this.city}`);
  }
}

let person1 = new Person("Arjun", 21, "Mumbai");
let person2 = new Person("Priya", 24, "Delhi");
let person3 = new Person("Rohan", 19, "Bangalore");

person1.greet();      // Hi, I am Arjun from Mumbai.
person2.greet();      // Hi, I am Priya from Delhi.
person3.greet();      // Hi, I am Rohan from Bangalore.

person1.birthday();   // Happy birthday Arjun! You are now 22.
person1.introduce();  // Name: Arjun | Age: 22 | City: Mumbai

// Create an array of person objects — very common real-world pattern
let people = [person1, person2, person3];

for (let person of people) {
  person.introduce();
}

// Output:
// Name: Arjun | Age: 22 | City: Mumbai
// Name: Priya | Age: 24 | City: Delhi
// Name: Rohan | Age: 19 | City: Bangalore
</code></pre>
<p>One class, three objects, one loop. This is exactly what OOP is for — creating many instances of the same structure without repeating code.</p>
<hr />
<h2>Classes vs Manual Objects</h2>
<p>To make the benefit concrete, here is the same data expressed both ways:</p>
<pre><code class="language-js">// Without a class — every object created manually
let user1 = { name: "Arjun", age: 21 };
let user2 = { name: "Priya", age: 24 };
let user3 = { name: "Rohan", age: 19 };

// No shared methods — you'd have to add greet() to each manually
// No guarantee they have the same shape
// Harder to maintain as the app grows

// ─────────────────────────────────────────────────────────
// With a class — one definition, consistent structure always

class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  greet() {
    console.log(`Hi, I am ${this.name}.`);
  }
}

let user1 = new User("Arjun", 21);
let user2 = new User("Priya", 24);
let user3 = new User("Rohan", 19);

// Every user automatically has greet()
user1.greet(); // Hi, I am Arjun.
user2.greet(); // Hi, I am Priya.
user3.greet(); // Hi, I am Rohan.
</code></pre>
<hr />
<h2>Encapsulation — Keeping Things Together</h2>
<p>Encapsulation is one of the core principles of OOP. The idea is simple: the data and the behavior that operates on that data should live in the same place.</p>
<p>Before OOP, you might have:</p>
<pre><code class="language-js">// Data and behavior are separate — easy to lose track of what belongs together
let studentName = "Priya";
let studentAge = 20;

function printStudentDetails(name, age) {
  console.log(`\({name} is \){age} years old.`);
}

printStudentDetails(studentName, studentAge);
</code></pre>
<p>With encapsulation, the data (<code>name</code>, <code>age</code>) and the behavior (<code>printStudentDetails</code>) are bundled inside the same class:</p>
<pre><code class="language-js">// Data and behavior live together — one clean unit
class Student {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  printDetails() {
    console.log(`\({this.name} is \){this.age} years old.`);
  }
}

let student = new Student("Priya", 20);
student.printDetails(); // Priya is 20 years old.
</code></pre>
<p>The function <code>printDetails</code> no longer needs to receive <code>name</code> and <code>age</code> as parameters — it already has access to them through <code>this</code>, because they are part of the same object. That is encapsulation: related things are enclosed in the same container.</p>
<hr />
<h2>Class → Instance Visual</h2>
<pre><code class="language-plaintext">              CLASS (blueprint — defined once)
             ┌─────────────────────────────────┐
             │  class Person {                 │
             │    constructor(name, age, city) │
             │    greet()                      │
             │    introduce()                  │
             │  }                              │
             └──────────────┬──────────────────┘
                            │
              new Person()  │  called three times
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
    ┌──────────────┐ ┌────────────┐ ┌───────────────┐
    │   person1    │ │  person2   │ │    person3    │
    │ ──────────── │ │ ────────── │ │ ─────────── │ │
    │ name:"Arjun" │ │name:"Priya"│ │name:"Rohan"   │
    │ age: 21      │ │ age: 24    │ │ age: 19       │
    │ city:"Mumbai"│ │city:"Delhi"│ │city:"Bangalore│
    │              │ │            │ │               │
    │ greet()  ✔   │ │ greet() ✔  │ │ greet()  ✔    │
    │ introduce() ✔│ │introduce()✔│ │introduce() ✔  │
    └──────────────┘ └────────────┘ └───────────────┘
      (instance 1)    (instance 2)    (instance 3)
</code></pre>
<p>Each instance has its own data but shares the methods defined in the class.</p>
<hr />
<h2>Assignment: Try It Yourself</h2>
<h3>Step 1: Create a <code>Student</code> class with a constructor</h3>
<pre><code class="language-js">class Student {
  constructor(name, age, course) {
    this.name = name;
    this.age = age;
    this.course = course;
  }

  printDetails() {
    console.log(`Name: \({this.name} | Age: \){this.age} | Course: ${this.course}`);
  }

  study(subject) {
    console.log(`\({this.name} is studying \){subject}.`);
  }
}
</code></pre>
<h3>Step 2: Create multiple student objects</h3>
<pre><code class="language-js">let student1 = new Student("Arjun", 21, "Computer Science");
let student2 = new Student("Priya", 20, "Mathematics");
let student3 = new Student("Rohan", 22, "Physics");
</code></pre>
<h3>Step 3: Call methods on each object</h3>
<pre><code class="language-js">student1.printDetails(); // Name: Arjun | Age: 21 | Course: Computer Science
student2.printDetails(); // Name: Priya | Age: 20 | Course: Mathematics
student3.printDetails(); // Name: Rohan | Age: 22 | Course: Physics

student1.study("Data Structures"); // Arjun is studying Data Structures.
</code></pre>
<h3>Step 4: Update a property and verify</h3>
<pre><code class="language-js">student1.age = 22;
student1.printDetails(); // Name: Arjun | Age: 22 | Course: Computer Science
</code></pre>
<h3>Step 5: Loop through an array of students</h3>
<pre><code class="language-js">let students = [student1, student2, student3];

console.log("All students:");
for (let student of students) {
  student.printDetails();
}

// Output:
// All students:
// Name: Arjun | Age: 22 | Course: Computer Science
// Name: Priya | Age: 20 | Course: Mathematics
// Name: Rohan | Age: 22 | Course: Physics
</code></pre>
<hr />
<h2>Quick Recap</h2>
<ul>
<li><p><strong>OOP</strong> organizes code around objects that combine data and behavior</p>
</li>
<li><p>A <strong>class</strong> is a blueprint — it defines the shape of an object but is not an object itself</p>
</li>
<li><p>An <strong>instance</strong> is an actual object created from a class using <code>new</code></p>
</li>
<li><p>The <strong>constructor</strong> runs automatically when a new instance is created and sets up its data</p>
</li>
<li><p><strong>Methods</strong> are functions inside a class that every instance can use</p>
</li>
<li><p><code>this</code> refers to the specific instance the method is running on</p>
</li>
<li><p><strong>Encapsulation</strong> means keeping related data and behavior together in one class</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[JavaScript Objects: Storing Related Data Together]]></title><description><![CDATA[So far in this series we have stored individual values in variables and lists of similar values in arrays. But what happens when you need to store several different pieces of information that all belo]]></description><link>https://blogs.arnabsamanta.in/javascript-objects-storing-related-data-together</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/javascript-objects-storing-related-data-together</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Fri, 13 Mar 2026 07:22:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/7c25ebcb-f99a-40c1-9ad8-4e9bafd31aef.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>So far in this series we have stored individual values in variables and lists of similar values in arrays. But what happens when you need to store several <em>different</em> pieces of information that all belong to the same thing?</p>
<p>Say you want to represent a person. A person has a name, an age, a city, and maybe an email. You could store each piece separately:</p>
<pre><code class="language-js">let name = "Arjun";
let age = 21;
let city = "Mumbai";
let email = "arjun@example.com";
</code></pre>
<p>This works until you need to represent five people. Now you have twenty variables with no clear connection between them. There is no way to know that <code>name</code>, <code>age</code>, <code>city</code>, and <code>email</code> all belong to the same person.</p>
<p>Objects solve this. An object groups all the related data under one variable, with named labels for each piece.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
  email: "arjun@example.com",
};
</code></pre>
<p>One variable. Four labeled pieces of data. All clearly related.</p>
<hr />
<h2>What is an Object?</h2>
<p>An object is a collection of <strong>key-value pairs</strong>. Each piece of data has a <strong>key</strong> (a label, always a string) and a <strong>value</strong> (whatever you want to store there).</p>
<pre><code class="language-plaintext">Object: person
┌─────────────────────────────────────────────────┐
│   Key          │   Value                        │
├────────────────┼────────────────────────────────┤
│   "name"       │   "Arjun"                      │
│   "age"        │   21                           │
│   "city"       │   "Mumbai"                     │
│   "email"      │   "arjun@example.com"          │
└────────────────┴────────────────────────────────┘

Access with:  person.name  →  "Arjun"
              person.age   →  21
</code></pre>
<p>The keys are sometimes called <strong>properties</strong>. The phrase "an object's property" just means one of its key-value pairs.</p>
<hr />
<h2>Arrays vs Objects</h2>
<p>Before going further, it helps to see exactly when to use each:</p>
<pre><code class="language-plaintext">ARRAY                               OBJECT
────────────────────────────────    ──────────────────────────────────────
let fruits = [                      let person = {
  "apple",                            name: "Arjun",
  "banana",                           age: 21,
  "mango"                             city: "Mumbai"
];                                  };

Ordered list of similar items       Named properties on one thing
Access by index: fruits[0]          Access by key: person.name
Best for: collections               Best for: describing one entity
</code></pre>
<p>Use an <strong>array</strong> when you have a list of similar things (fruits, scores, names). Use an <strong>object</strong> when you are describing one thing with multiple different attributes (a person, a product, a user profile).</p>
<hr />
<h2>Creating an Object</h2>
<p>Objects are created using curly braces <code>{}</code>. Each key-value pair is separated by a comma, and the key and value are separated by a colon.</p>
<pre><code class="language-js">// Basic syntax
let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
};

// Object with mixed value types
let product = {
  title: "Mechanical Keyboard",
  price: 3499,
  inStock: true,
  rating: 4.5,
};

// Object with an array as a value
let student = {
  name: "Priya",
  marks: [88, 92, 75, 96],
  passed: true,
};

// An empty object — you can add properties later
let config = {};
</code></pre>
<p>The keys do not need quotes when they are simple words. If a key contains spaces or special characters, you must wrap it in quotes:</p>
<pre><code class="language-js">let profile = {
  firstName: "Arjun",          // no quotes needed
  "last name": "Sharma",       // quotes required — has a space
  "fav-color": "blue",         // quotes required — has a hyphen
};
</code></pre>
<hr />
<h2>Accessing Properties</h2>
<p>There are two ways to read a value from an object.</p>
<h3>Dot notation</h3>
<p>The most common way. Write the object name, a dot, then the key name.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
};

console.log(person.name);  // "Arjun"
console.log(person.age);   // 21
console.log(person.city);  // "Mumbai"

// Accessing a key that does not exist returns undefined
console.log(person.email); // undefined
</code></pre>
<h3>Bracket notation</h3>
<p>Write the object name, then the key as a string inside square brackets. This is the same idea as accessing an array by index, except you use a string key instead of a number.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
};

console.log(person["name"]);  // "Arjun"
console.log(person["age"]);   // 21
console.log(person["city"]);  // "Mumbai"
</code></pre>
<p>Bracket notation becomes necessary in two situations. First, when the key contains special characters:</p>
<pre><code class="language-js">let profile = {
  "last name": "Sharma",
  "fav-color": "blue",
};

// This would fail:
// console.log(profile.last name); — syntax error

// This works:
console.log(profile["last name"]);  // "Sharma"
console.log(profile["fav-color"]);  // "blue"
</code></pre>
<p>Second, when the key is stored in a variable:</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
};

let key = "age";
console.log(person[key]);  // 21 — uses the value of the variable as the key

key = "city";
console.log(person[key]);  // "Mumbai"
</code></pre>
<p>This is something dot notation simply cannot do. If you write <code>person.key</code>, JavaScript looks for a property literally named <code>"key"</code>, not the value of the variable <code>key</code>.</p>
<hr />
<h2>Updating Properties</h2>
<p>Updating an existing property uses the same syntax as creating one — assign a new value to the key.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
};

console.log(person.age);  // 21

// Update the age
person.age = 22;
console.log(person.age);  // 22

// Update using bracket notation
person["city"] = "Pune";
console.log(person.city); // "Pune"

console.log(person);
// { name: "Arjun", age: 22, city: "Pune" }
</code></pre>
<hr />
<h2>Adding New Properties</h2>
<p>You can add a property to an object at any time after it was created — just assign to a key that does not yet exist.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
};

// Adding new properties after creation
person.city = "Mumbai";
person.email = "arjun@example.com";
person["phone"] = "9876543210";

console.log(person);
// {
//   name: "Arjun",
//   age: 21,
//   city: "Mumbai",
//   email: "arjun@example.com",
//   phone: "9876543210"
// }
</code></pre>
<hr />
<h2>Deleting Properties</h2>
<p>Use the <code>delete</code> operator to remove a property from an object entirely.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
  email: "arjun@example.com",
};

console.log(person.email); // "arjun@example.com"

delete person.email;

console.log(person.email); // undefined — property no longer exists
console.log(person);
// { name: "Arjun", age: 21, city: "Mumbai" }
</code></pre>
<p>After deletion, accessing the removed key returns <code>undefined</code>, just like accessing any key that was never there.</p>
<hr />
<h2>Looping Through an Object</h2>
<p>Unlike arrays, objects do not have numbered indices — they have named keys. To iterate over all key-value pairs, use a <code>for...in</code> loop.</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
  email: "arjun@example.com",
};

// for...in gives you each key one at a time
for (let key in person) {
  console.log(key + ": " + person[key]);
}

// Output:
// name: Arjun
// age: 21
// city: Mumbai
// email: arjun@example.com
</code></pre>
<p>Notice that inside the loop, <code>person[key]</code> uses bracket notation with a variable — this is exactly the situation where dot notation would not work.</p>
<p>You can also use <code>Object.keys()</code> to get all the keys as an array, then loop over that:</p>
<pre><code class="language-js">let person = {
  name: "Arjun",
  age: 21,
  city: "Mumbai",
};

let keys = Object.keys(person);
console.log(keys); // ["name", "age", "city"]

for (let i = 0; i &lt; keys.length; i++) {
  let key = keys[i];
  console.log(key + " → " + person[key]);
}

// Output:
// name → Arjun
// age → 21
// city → Mumbai
</code></pre>
<p>And <code>Object.values()</code> if you only need the values:</p>
<pre><code class="language-js">let person = { name: "Arjun", age: 21, city: "Mumbai" };

let values = Object.values(person);
console.log(values); // ["Arjun", 21, "Mumbai"]
</code></pre>
<hr />
<h2>Object Key-Value Structure Diagram</h2>
<pre><code class="language-plaintext">Variable         Object in memory
────────         ──────────────────────────────────────────
                 ┌─────────────────────────────────────────┐
                 │              person                     │
person  ──────►  ├───────────────┬─────────────────────────┤
                 │     KEY       │         VALUE           │
                 ├───────────────┼─────────────────────────┤
                 │  "name"       │  "Arjun"                │
                 ├───────────────┼─────────────────────────┤
                 │  "age"        │  21                     │
                 ├───────────────┼─────────────────────────┤
                 │  "city"       │  "Mumbai"               │
                 ├───────────────┼─────────────────────────┤
                 │  "email"      │  "arjun@example.com"    │
                 └───────────────┴─────────────────────────┘

person.name      ─────────────────────────────►  "Arjun"
person["age"]    ─────────────────────────────►  21
person.city      ─────────────────────────────►  "Mumbai"
</code></pre>
<hr />
<h2>Assignment: Try It Yourself</h2>
<p>Open your browser console or <a href="http://playcode.io">playcode.io</a> and work through these steps.</p>
<h3>Step 1: Create a student object</h3>
<pre><code class="language-js">let student = {
  name: "Priya",
  age: 20,
  course: "Computer Science",
};
</code></pre>
<h3>Step 2: Add a new property</h3>
<pre><code class="language-js">student.college = "MIT Pune";
console.log(student);
// { name: "Priya", age: 20, course: "Computer Science", college: "MIT Pune" }
</code></pre>
<h3>Step 3: Update one property</h3>
<pre><code class="language-js">student.age = 21;
console.log("Updated age:", student.age); // 21
</code></pre>
<h3>Step 4: Print all keys and values using a loop</h3>
<pre><code class="language-js">console.log("Student details:");
for (let key in student) {
  console.log(key + ": " + student[key]);
}

// Output:
// Student details:
// name: Priya
// age: 21
// course: Computer Science
// college: MIT Pune
</code></pre>
<h3>Bonus: Delete a property and verify it is gone</h3>
<pre><code class="language-js">delete student.college;
console.log(student.college); // undefined
console.log(student);
// { name: "Priya", age: 21, course: "Computer Science" }
</code></pre>
<hr />
<h2>Quick Recap</h2>
<ul>
<li><p>An <strong>object</strong> is a collection of key-value pairs used to describe a single entity</p>
</li>
<li><p>Created with curly braces: <code>let obj = { key: value }</code></p>
</li>
<li><p>Access properties with <strong>dot notation</strong> (<code>obj.key</code>) or <strong>bracket notation</strong> (<code>obj["key"]</code>)</p>
</li>
<li><p>Use bracket notation when the key has special characters or is stored in a variable</p>
</li>
<li><p><strong>Update</strong> a property by assigning a new value: <code>obj.key = newValue</code></p>
</li>
<li><p><strong>Add</strong> a property by assigning to a new key: <code>obj.newKey = value</code></p>
</li>
<li><p><strong>Delete</strong> a property with the <code>delete</code> operator: <code>delete obj.key</code></p>
</li>
<li><p><strong>Loop</strong> through keys with <code>for...in</code> or <code>Object.keys()</code></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[JavaScript Functions: Declaration vs Expression]]></title><description><![CDATA[If you have written even a little JavaScript, you have probably copy-pasted code more than once. You wrote the same logic in two places and told yourself you would clean it up later. Functions are exa]]></description><link>https://blogs.arnabsamanta.in/javascript-functions-declaration-vs-expression</link><guid isPermaLink="true">https://blogs.arnabsamanta.in/javascript-functions-declaration-vs-expression</guid><dc:creator><![CDATA[arnab samanta]]></dc:creator><pubDate>Fri, 13 Mar 2026 07:07:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65b4e73f6da009476b4a0dd5/0d10012a-74d6-4a9f-88e6-279b13db94da.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you have written even a little JavaScript, you have probably copy-pasted code more than once. You wrote the same logic in two places and told yourself you would clean it up later. Functions are exactly that cleanup. They let you write a piece of logic once, give it a name, and call it whenever you need it.</p>
<p>This article covers what functions are, the two main ways to write them, and a real practical difference between them — hoisting — explained without any jargon.</p>
<hr />
<h2>Why Functions Exist</h2>
<p>Consider this code that greets three different people:</p>
<pre><code class="language-js">// Without functions — repeating the same logic
console.log("Hello, Arjun! Welcome.");
console.log("Hello, Priya! Welcome.");
console.log("Hello, Rohan! Welcome.");
</code></pre>
<p>Now imagine you need to change the greeting from "Welcome" to "Good to see you." You update three lines. If there were thirty names, you update thirty lines. This is the problem functions solve.</p>
<pre><code class="language-js">// With a function — write the logic once, use it anywhere
function greet(name) {
  console.log("Hello, " + name + "! Good to see you.");
}

greet("Arjun"); // Hello, Arjun! Good to see you.
greet("Priya"); // Hello, Priya! Good to see you.
greet("Rohan"); // Hello, Rohan! Good to see you.
</code></pre>
<p>Now if the greeting changes, you update one place and every call benefits. That is the core idea: <strong>functions are reusable, named blocks of code</strong>.</p>
<hr />
<h2>Anatomy of a Function</h2>
<p>Before looking at the two syntax styles, here is what every function is made of:</p>
<pre><code class="language-plaintext">function greet ( name ) {
│        │       │       │
│        │       │       └── body: the code that runs
│        │       └────────── parameter: input the function accepts
│        └────────────────── name: how you call it
└─────────────────────────── keyword
</code></pre>
<ul>
<li><p><strong>Parameters</strong> are the variables listed in the parentheses when you <em>define</em> the function.</p>
</li>
<li><p><strong>Arguments</strong> are the actual values you pass when you <em>call</em> the function.</p>
</li>
<li><p>The <strong>return value</strong> is what the function sends back after it finishes.</p>
</li>
</ul>
<pre><code class="language-js">// name is the parameter
function greet(name) {
  return "Hello, " + name; // return sends a value back
}

// "Arjun" is the argument
let message = greet("Arjun");
console.log(message); // "Hello, Arjun"
</code></pre>
<hr />
<h2>Function Declaration</h2>
<p>A function declaration is the most straightforward way to define a function. You use the <code>function</code> keyword followed by a name, and the body goes inside curly braces.</p>
<pre><code class="language-js">// Function declaration
function add(a, b) {
  return a + b;
}

// Calling it
let result = add(5, 3);
console.log(result); // 8
</code></pre>
<p>A few more examples to make the pattern concrete:</p>
<pre><code class="language-js">// No parameters, no return value
function sayHello() {
  console.log("Hello!");
}
sayHello(); // Hello!

// One parameter
function double(n) {
  return n * 2;
}
console.log(double(7)); // 14

// Multiple parameters
function fullName(first, last) {
  return first + " " + last;
}
console.log(fullName("Arjun", "Sharma")); // "Arjun Sharma"

// Used in a calculation
function calculateArea(length, width) {
  return length * width;
}
let area = calculateArea(10, 5);
console.log("Area:", area); // Area: 50
</code></pre>
<hr />
<h2>Function Expression</h2>
<p>A function expression assigns a function to a variable. Instead of giving the function a name directly after the <code>function</code> keyword, you create the function and store it in a variable — just like you would store a number or a string.</p>
<pre><code class="language-js">// Function expression
const add = function(a, b) {
  return a + b;
};

// Calling it — same as before
let result = add(5, 3);
console.log(result); // 8
</code></pre>
<p>The function on the right side of <code>=</code> has no name of its own — it is called an <strong>anonymous function</strong>. The variable <code>add</code> holds a reference to it.</p>
<pre><code class="language-js">// The same examples rewritten as expressions

const sayHello = function() {
  console.log("Hello!");
};
sayHello(); // Hello!

const double = function(n) {
  return n * 2;
};
console.log(double(7)); // 14

const fullName = function(first, last) {
  return first + " " + last;
};
console.log(fullName("Arjun", "Sharma")); // "Arjun Sharma"

const calculateArea = function(length, width) {
  return length * width;
};
let area = calculateArea(10, 5);
console.log("Area:", area); // Area: 50
</code></pre>
<p>The behavior is identical. The difference is entirely in how and when JavaScript makes the function available — which brings us to hoisting.</p>
<hr />
<h2>Hoisting: The Key Practical Difference</h2>
<p>Hoisting is what JavaScript does before it runs your code. The engine scans your file first and pulls certain declarations to the top of their scope. Function declarations are hoisted completely — both the name and the body. Function expressions are not.</p>
<p>This means you can call a function declaration <em>before</em> the line where you wrote it, and it works. Try the same thing with a function expression and you get an error.</p>
<pre><code class="language-js">// Calling a declaration BEFORE it is defined — works fine
let result = add(4, 6);
console.log(result); // 10

function add(a, b) {
  return a + b;
}
</code></pre>
<p>JavaScript moved the entire <code>add</code> function to the top before running anything. By the time <code>add(4, 6)</code> runs, the function already exists.</p>
<pre><code class="language-js">// Calling an expression BEFORE it is defined — throws an error
let result = multiply(4, 6); // ReferenceError: Cannot access 'multiply' before initialization

const multiply = function(a, b) {
  return a * b;
};
</code></pre>
<p>With expressions, the variable <code>multiply</code> is created but its value (the function) is not assigned until that line executes. Calling it before that point throws an error.</p>
<p>Here is a side-by-side summary:</p>
<pre><code class="language-plaintext">DECLARATION                          EXPRESSION
──────────────────────────────────── ──────────────────────────────────────
function add(a, b) {                 const add = function(a, b) {
  return a + b;                        return a + b;
}                                    };

✔ Can be called before definition    ✘ Cannot be called before definition
✔ Hoisted fully by JavaScript        ✘ Variable hoisted, value is not
✔ Has its own name                   ✘ Anonymous (no name on the function)
</code></pre>
<hr />
<h2>Comparison Table</h2>
<table>
<thead>
<tr>
<th></th>
<th>Function Declaration</th>
<th>Function Expression</th>
</tr>
</thead>
<tbody><tr>
<td>Syntax</td>
<td><code>function name() {}</code></td>
<td><code>const name = function() {}</code></td>
</tr>
<tr>
<td>Hoisted?</td>
<td>Yes — fully</td>
<td>No — throws if called early</td>
</tr>
<tr>
<td>Has a name?</td>
<td>Yes</td>
<td>Usually anonymous</td>
</tr>
<tr>
<td>Ends with <code>;</code>?</td>
<td>No</td>
<td>Yes (it's an assignment)</td>
</tr>
<tr>
<td>When available</td>
<td>Entire scope immediately</td>
<td>Only after the line runs</td>
</tr>
</tbody></table>
<hr />
<h2>Execution Flow of a Function Call</h2>
<p>Here is what happens step by step when JavaScript runs a function call:</p>
<pre><code class="language-plaintext">Your Code                          What JavaScript Does
─────────────────────────          ──────────────────────────────────────
                                   1. Scans file, hoists declarations
let result = add(4, 6);  ───────►  2. Calls add with arguments 4 and 6
                                   3. Jumps into function body
                                      a = 4, b = 6
function add(a, b) {               4. Executes: return 4 + 6
  return a + b;          ◄───────  5. Returns 10 back to the call site
}
                                   6. result = 10
console.log(result);     ───────►  7. Prints 10
</code></pre>
<p>For a function expression, step 1 changes — the function is <em>not</em> hoisted, so calling it before the assignment line causes the engine to stop with an error.</p>
<hr />
<h2>When to Use Each</h2>
<p><strong>Use a function declaration when:</strong></p>
<ul>
<li><p>The function is a core part of your program (a utility you call throughout the file)</p>
</li>
<li><p>You want the flexibility to call it anywhere in the file without worrying about order</p>
</li>
<li><p>You are defining named, standalone pieces of logic</p>
</li>
</ul>
<pre><code class="language-js">// Good candidate for a declaration — used throughout the file
function formatCurrency(amount) {
  return "₹" + amount.toFixed(2);
}

console.log(formatCurrency(1500));   // ₹1500.00
console.log(formatCurrency(99.9));   // ₹99.90
</code></pre>
<p><strong>Use a function expression when:</strong></p>
<ul>
<li><p>You are passing a function as an argument to another function</p>
</li>
<li><p>You want to conditionally assign different functions to a variable</p>
</li>
<li><p>You are writing a function that should only exist in a specific scope</p>
</li>
</ul>
<pre><code class="language-js">// Good candidate for an expression — assigned conditionally
let greet;

const isLoggedIn = true;

if (isLoggedIn) {
  greet = function(name) {
    return "Welcome back, " + name + "!";
  };
} else {
  greet = function(name) {
    return "Hello, " + name + ". Please log in.";
  };
}

console.log(greet("Arjun")); // "Welcome back, Arjun!"
</code></pre>
<p>Both are valid. Most developers use declarations for main logic and expressions for callbacks, conditional assignments, and short inline functions.</p>
<hr />
<h2>Assignment: Try It Yourself</h2>
<p>Open your browser console or <a href="http://playcode.io">playcode.io</a> and work through these steps.</p>
<h3>Step 1: Write a function declaration that multiplies two numbers</h3>
<pre><code class="language-js">function multiply(a, b) {
  return a * b;
}
</code></pre>
<h3>Step 2: Write the same logic as a function expression</h3>
<pre><code class="language-js">const multiplyExpr = function(a, b) {
  return a * b;
};
</code></pre>
<h3>Step 3: Call both and print the results</h3>
<pre><code class="language-js">let result1 = multiply(6, 7);
let result2 = multiplyExpr(6, 7);

console.log("Declaration result:", result1); // 42
console.log("Expression result:", result2);  // 42
</code></pre>
<h3>Step 4: Try calling them before defining — observe the difference</h3>
<pre><code class="language-js">// Test 1: Call the declaration before its definition
console.log(multiplyEarly(4, 5)); // 20 — works because of hoisting

function multiplyEarly(a, b) {
  return a * b;
}

// Test 2: Call the expression before its definition
console.log(multiplyLate(4, 5)); // ReferenceError — not hoisted

const multiplyLate = function(a, b) {
  return a * b;
};
</code></pre>
<p>Run Test 1 first, see it print <code>20</code>. Then run Test 2 and observe the <code>ReferenceError</code>. That single experiment makes the hoisting difference completely clear.</p>
<hr />
<h2>Quick Recap</h2>
<ul>
<li><p>Functions are <strong>reusable blocks of code</strong> that take inputs, do work, and optionally return a value</p>
</li>
<li><p><strong>Function declarations</strong> use <code>function name() {}</code> and are fully hoisted — callable anywhere in the file</p>
</li>
<li><p><strong>Function expressions</strong> assign a function to a variable: <code>const name = function() {}</code> — only available after that line runs</p>
</li>
<li><p><strong>Hoisting</strong> is JavaScript pre-scanning declarations before executing code — declarations benefit from it, expressions do not</p>
</li>
<li><p>Use declarations for standalone utility functions, expressions for callbacks and conditional assignments</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>