<?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[Sameer's Dev Log]]></title><description><![CDATA[Developer blog - notes, experiments, and learnings across tech.]]></description><link>https://blog.sameerbhagtani.dev</link><generator>RSS for Node</generator><lastBuildDate>Fri, 09 Oct 2026 04:41:10 GMT</lastBuildDate><atom:link href="https://blog.sameerbhagtani.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[React Virtual DOM Explained: How It Works Under the Hood]]></title><description><![CDATA[Introduction
If you've ever built something with vanilla JavaScript and had to update the UI frequently, you already know the pain. You call document.getElementById, change some text, update a class, ]]></description><link>https://blog.sameerbhagtani.dev/react-virtual-dom-explained</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/react-virtual-dom-explained</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[React]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[virtual dom]]></category><category><![CDATA[MERN Stack]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Fri, 08 May 2026 20:33:03 GMT</pubDate><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've ever built something with vanilla JavaScript and had to update the UI frequently, you already know the pain. You call <code>document.getElementById</code>, change some text, update a class, maybe re-render a list. It works. But at some point, as the app grows, it slows to a crawl. Pages feel sluggish. Simple interactions feel heavier than they should.</p>
<p>That sluggishness has a cause. And the Virtual DOM is React's answer to it.</p>
<hr />
<h2>The Problem with Direct DOM Manipulation</h2>
<p>The real DOM (Document Object Model) is a tree of nodes that the browser builds from your HTML. Every time you touch it, the browser has to do work.</p>
<p>Change a single element's text? The browser may reflow the layout. Add a class? It might repaint parts of the screen. Remove a child node and add a new one? It recalculates styles, repaints, and composites everything again.</p>
<p>These operations are not free. The DOM was built to represent documents, not dynamic user interfaces that update dozens of times per second. When you write a loop that calls <code>innerHTML</code> repeatedly, or update many nodes in quick succession, you're forcing the browser to redo expensive work on every single change.</p>
<p>React solves it by introducing a layer between your code and the real DOM.</p>
<hr />
<h2>What the Virtual DOM Actually Is</h2>
<p>The Virtual DOM is not magic. It's a plain JavaScript object that describes what the UI should look like.</p>
<p>When you write JSX like this:</p>
<pre><code class="language-javascript">const element = &lt;h1 className="title"&gt;Hello&lt;/h1&gt;;
</code></pre>
<p>React converts it into something like this under the hood:</p>
<pre><code class="language-javascript">const element = {
    type: 'h1',
    props: {
        className: 'title',
        children: 'Hello'
    }
};
</code></pre>
<p>That's it. A JavaScript object. No browser APIs involved. No layout recalculations. Just a description of a node.</p>
<p>A full component tree becomes a tree of these objects. React holds this in memory and uses it to figure out what, if anything, needs to change in the real DOM. Since reading and writing plain JavaScript objects is orders of magnitude faster than touching the DOM, React can do a lot of computation cheaply before it ever commits a single change to the browser.</p>
<hr />
<h2>Step 1: The Initial Render</h2>
<p>When your app loads for the first time, React builds a Virtual DOM tree from your component tree, then walks it once to generate the corresponding real DOM nodes and insert them into the page.</p>
<pre><code class="language-plaintext">App
 └── Header
 │     └── h1: "My App"
 └── Main
       └── p: "Welcome"
</code></pre>
<p>React creates the equivalent real DOM elements, attaches event listeners, and paints the initial UI. This first render has no diffing to do. It just builds.</p>
<hr />
<h2>Step 2: Something Changes</h2>
<p>Now a user clicks a button. You call <code>setState</code>. A prop changes. React knows something has changed, so it needs to figure out what the new UI should look like.</p>
<p>The key thing here: React does not immediately touch the real DOM.</p>
<p>Instead, it re-runs your component functions (or render methods) to produce a brand new Virtual DOM tree that reflects the new state.</p>
<pre><code class="language-plaintext">// Old Virtual DOM tree
App
 └── Counter
       └── p: "Count: 0"
       └── button: "Increment"

// New Virtual DOM tree (after state change)
App
 └── Counter
       └── p: "Count: 1"   &lt;--- changed
       └── button: "Increment"
</code></pre>
<p>Both trees exist in memory. Now React has to compare them.</p>
<hr />
<h2>Step 3: Diffing (Reconciliation)</h2>
<p>Reconciliation is the process of comparing the old Virtual DOM tree with the new one, node by node, to find what changed.</p>
<p>React calls this diffing. Walking through the two trees looks roughly like this:</p>
<pre><code class="language-plaintext">Old Tree              New Tree
-----------           -----------
App                   App
 └── Counter           └── Counter
       └── p: "0"            └── p: "1"   &lt;- different
       └── button             └── button  &lt;- same
</code></pre>
<p>React starts at the root and walks both trees in parallel. For each node, it asks: is this the same type of element? Do the props match? What about the children?</p>
<p>In this case, it finds one difference: the text content of the <code>p</code> tag changed from <code>"0"</code> to <code>"1"</code>. Everything else is identical.</p>
<p>React does not re-render the button. It does not re-render the Counter wrapper. It marks only that one <code>p</code> node as needing an update.</p>
<p>A few rules React uses to make this fast:</p>
<ul>
<li><p>Elements of different types (like swapping a <code>div</code> for a <code>span</code>) are treated as a full replacement. The old subtree is discarded and a new one is built.</p>
</li>
<li><p>For elements of the same type, React updates only the changed attributes or children.</p>
</li>
<li><p>For lists, React uses <code>key</code> props to match old items to new ones. Without keys, React has to guess, which can produce wrong results.</p>
</li>
</ul>
<hr />
<h2>Step 4: The Commit Phase</h2>
<p>Once diffing is done, React has a list of the minimal changes it needs to make. It then applies those changes to the real DOM in a single batch.</p>
<p>In the example above, it does one thing: updates the text content of that paragraph. Not the button. Not the wrapper. Just the text.</p>
<pre><code class="language-plaintext">// Only this real DOM operation runs:
paragraphNode.textContent = "Count: 1";
</code></pre>
<p>This batching is where the performance benefit becomes real. Instead of updating the DOM after every <code>setState</code> call individually, React collects all the changes from a render cycle and applies them at once. The browser does one reflow and one repaint, not many.</p>
<hr />
<h2>The Full Flow</h2>
<p>Here's the flow from start to finish:</p>
<pre><code class="language-plaintext">[State/Props Change]
        |
        v
[React re-runs components]
[New Virtual DOM tree is created]
        |
        v
[Diffing: old tree vs new tree]
[Minimal list of changes is computed]
        |
        v
[Commit phase: changes applied to real DOM]
        |
        v
[Browser repaints]
</code></pre>
<p>React separates the "figuring out what changed" step (render and diff) from the "actually changing the DOM" step (commit). The first part is cheap. The second part is expensive. By minimizing how often and how much of the second part runs, React keeps UIs fast.</p>
<hr />
<h2>Is the Virtual DOM Always Worth It?</h2>
<p>You might write a component that re-renders on every keystroke. Without Virtual DOM, that would mean dozens of DOM writes per second. With React's approach, most of those re-renders produce a Virtual DOM that's nearly identical to the previous one. After diffing, maybe only one input's value attribute gets updated in the real DOM.</p>
<p>The Virtual DOM doesn't eliminate DOM work. It reduces it to only what's necessary.</p>
<p>There's a tradeoff worth knowing: for extremely simple UIs, the overhead of maintaining a Virtual DOM and diffing it isn't worth it. Vanilla JavaScript can be faster for small, static pages. But once your UI has real complexity and frequent updates, the Virtual DOM approach pays off quickly.</p>
<hr />
<h2>Conclusion</h2>
<p>The mental model here, render to a virtual tree, diff it against the previous tree, commit only the changes, is accurate enough to write better React code, debug re-render issues, and understand why <code>key</code> props matter in lists.</p>
<p>That's the Virtual DOM. A JavaScript object tree, a comparison algorithm, and a batched write to the real DOM. Nothing more, nothing less.</p>
]]></content:encoded></item><item><title><![CDATA[Behind the Root: Linux Filesystem Demystified]]></title><description><![CDATA[Introduction
If you've ever installed and tried out Linux after seeing a cool hacking sequence in a sci-fi movie, you know that opening it feels like stepping into a strange city with many roads named]]></description><link>https://blog.sameerbhagtani.dev/linux-filesystem-demystified</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/linux-filesystem-demystified</guid><category><![CDATA[Linux]]></category><category><![CDATA[networking]]></category><category><![CDATA[Security]]></category><category><![CDATA[dns]]></category><category><![CDATA[file system]]></category><category><![CDATA[ChaiCode]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Wed, 22 Apr 2026 17:08:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/21030a96-1b8a-4e35-93df-a51fdc10e5ca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've ever installed and tried out Linux after seeing a cool hacking sequence in a sci-fi movie, you know that opening it feels like stepping into a strange city with many roads named <code>/bin</code>, <code>/home</code> and <code>/tmp</code>. As beginners, we tend to ignore them and go on with our Linux usage by simply remembering the most commonly used commands.</p>
<p>While that approach works initially, it is good to take a step back and understand the Linux Filesystem properly. As "good" developers, who actually get their code out of <code>localhost</code>, we need to understand Linux to its core, because that is what drives the majority of web servers.</p>
<p>In this blog post, I have broken down the philosophy behind the Linux Filesystem, what all those randomly named directories actually do, and some cool insights along the way.</p>
<hr />
<h2>The Core Philosophy: Everything is a File</h2>
<p>A fascinating thing about Linux is that everything, literally everything in Linux, is represented as a file in the Filesystem. This includes not just documents, but devices, processes, sockets, and even hardware!</p>
<p>To digest this idea properly, we need to change our perspective on what a "file" actually means. We usually think of a "file" as a document on our system. In Linux though, a "file" is just a stream of bytes with a path. That's it. Anything that can be read from or written to fits that definition.</p>
<p>Let's look at some examples of files as per this new definition:</p>
<table>
<thead>
<tr>
<th>Path</th>
<th>Description</th>
</tr>
</thead>
<tbody><tr>
<td><code>/home/user/gta-cheat-codes.txt</code></td>
<td>Just a simple file that the user has created</td>
</tr>
<tr>
<td><code>/dev/input/...</code></td>
<td>Your input devices like keyboard, mouse</td>
</tr>
<tr>
<td><code>/dev/sda</code></td>
<td>Literally your hard drive</td>
</tr>
<tr>
<td><code>/proc/1234</code></td>
<td>A running process</td>
</tr>
</tbody></table>
<p>Since everything is a file, you can do powerful things like pipe data between programs, redirect output, and chain tools together. This is the exact reason why the Linux terminal is so powerful.</p>
<p>This core philosophy is what gives the Linux Filesystem its structure.</p>
<hr />
<h2>Filesystem Hierarchy Standard (FHS)</h2>
<p>Before we dive deep into the directory structure, I want to mention that the Linux Filesystem isn't a random arrangement of resources in a tree-like structure. There is a specification called the "Filesystem Hierarchy Standard" that defines the directory structure and contents in Linux and other Unix-like operating systems. It is maintained by the Linux Foundation.</p>
<h3>The Problem it Solves</h3>
<p>Before FHS, different Unix distributions placed files wherever they wanted. A config file might live in <code>/etc</code> on one system and <code>/usr/config</code> on another. This made it a nightmare to:</p>
<ul>
<li><p>Write portable software</p>
</li>
<li><p>Move between distributions</p>
</li>
<li><p>Predict where anything lives</p>
</li>
</ul>
<p>FHS serves as a guideline, which most major distros like Debian, Fedora and Arch follow closely to maintain uniformity and predictability.</p>
<hr />
<h2>The Root Directory</h2>
<p>The root directory is the top of the entire filesystem tree in Linux. It is represented by <code>/</code>. The reason it is called the "root" is because there is nothing above it. You can go back as much as you want but never beyond the "root".</p>
<p>If you're from the Windows ecosystem, you can think of this as your <code>C:\</code>. Everything, including files, devices, processes, and external drives, all mount within this same tree.</p>
<p>We can run the <code>ls</code> command at the root of our linux system, and would get the following directories:</p>
<pre><code class="language-plaintext">/
├── bin     -&gt; Essential command binaries
├── boot    -&gt; Kernel and bootloader files
├── dev     -&gt; Device files to interface with hardware
├── etc     -&gt; Text-based configuration files
├── home    -&gt; Personal directories for each user
├── lib     -&gt; Shared library files used by binaries
├── media   -&gt; Mount point for removable media (USBs, CDs)
├── mnt     -&gt; Temporary mount point for filesystems
├── opt     -&gt; Optional, add-on software packages
├── proc    -&gt; Virtual filesystem tracking running processes
├── root    -&gt; Home directory for the root user
├── run     -&gt; Runtime data for processes since last boot
├── sbin    -&gt; System binaries for administrative use
├── srv     -&gt; Data served by the system (FTP, HTTP, etc.)
├── sys     -&gt; Virtual filesystem exposing kernel internals
├── tmp     -&gt; Temporary files, cleared on reboot
├── usr     -&gt; Secondary hierarchy for user installed software
└── var     -&gt; Variable data like logs, caches and spools
</code></pre>
<hr />
<h2><code>/etc</code>: System Configuration Hub</h2>
<p>I personally like to refer to it as the "Configuration Hub" of the entire system. The reason is that every major program, service, and system behavior has its config file here.</p>
<p>Moreover, it's all just plain text. This simple design choice makes configurations readable and easily editable. This is what makes Linux so customizable.</p>
<pre><code class="language-plaintext">/etc
├── hostname       -&gt; The machine's host name
├── hosts          -&gt; Local DNS overrides
├── nsswitch.conf  -&gt; Controls the order of lookups
├── resolv.conf    -&gt; DNS server configuration
├── network/       -&gt; Network interface configuration (Debian)
├── netplan/       -&gt; Network interface configuration (Ubuntu)
├── passwd         -&gt; User account information
├── shadow         -&gt; Hashed user passwords
├── group          -&gt; Group memberships
├── sudoers        -&gt; Controls who can run commands as root
├── environment    -&gt; System-wide environment variables
├── profile        -&gt; Shell environment on login
└── systemd/
    └── system/    -&gt; Service unit files
</code></pre>
<hr />
<h2>Password Storage</h2>
<p>Most people assume passwords are stored somewhere as plain text or in one file. Linux is much smarter than that. It splits user information across multiple files with specific jobs.</p>
<h3><code>/etc/passwd</code></h3>
<p>Despite the name, this file does not store passwords anymore. It stores user account information. Every line is one user, and it looks like this:</p>
<pre><code class="language-plaintext">root:x:0:0:root:/root:/bin/bash
sameer:x:1000:1000:Sameer Bhagtani:/home/sameer:/bin/bash
</code></pre>
<p>Each colon-separated field means:</p>
<ol>
<li><p>Username</p>
</li>
<li><p>Password field: just an <code>x</code>, meaning "go look in <code>/etc/shadow</code>"</p>
</li>
<li><p>UID: User ID, a unique number for the user</p>
</li>
<li><p>GID: Group ID, the user's primary group</p>
</li>
<li><p>GECOS: Full name or description</p>
</li>
<li><p>Home directory</p>
</li>
<li><p>Default shell</p>
</li>
</ol>
<h3><code>/etc/shadow</code></h3>
<p>This is where the actual passwords live. Linux doesn't store them in plain text format. Instead, it hashes the password for security.</p>
<p>This file is only readable by root. A line looks like:</p>
<pre><code class="language-plaintext">root:\(y\)j9T\(randomsalt\)hashedpasswordstring:20384::::::
</code></pre>
<p>Each colon-separated field means:</p>
<ol>
<li><p>Username</p>
</li>
<li><p>Hashed password</p>
</li>
<li><p>Last password change: days since Jan 1, 1970</p>
</li>
<li><p>Minimum password age: days before password can be changed</p>
</li>
<li><p>Maximum password age: days before password must be changed</p>
</li>
<li><p>Warning period: days before expiry to warn the user</p>
</li>
<li><p>Remaining fields: inactivity period, expiry date, reserved</p>
</li>
</ol>
<hr />
<h2>Groups</h2>
<p>A group in Linux is simply a collection of users. Linux uses groups to manage permissions at scale. Instead of setting permissions for each user individually, you assign permissions to a group and add users to it.</p>
<p>For example, you have 5 developers who all need access to <code>/var/www/</code>. Instead of giving each of them individual access, you create a <code>www-data</code> group, give the group access to that folder, and add all 5 users to it.</p>
<p>All this information is stored in <code>/etc/group</code>, where a line looks like:</p>
<pre><code class="language-plaintext">network:x:27:user1,user2
</code></pre>
<p>Each colon-separated field means:</p>
<ol>
<li><p>Group name</p>
</li>
<li><p>Password: almost always x or empty, group passwords are rarely used</p>
</li>
<li><p>GID: Group ID</p>
</li>
<li><p>Members: comma-separated list of users in the group</p>
</li>
</ol>
<h3>Default Groups</h3>
<p>Following are the meanings of some of the default groups in Linux:</p>
<table>
<thead>
<tr>
<th>Group</th>
<th>What it gives you access to</th>
</tr>
</thead>
<tbody><tr>
<td><code>wheel</code></td>
<td><code>sudo</code> privileges</td>
</tr>
<tr>
<td><code>audio</code></td>
<td>Sound devices</td>
</tr>
<tr>
<td><code>video</code></td>
<td>GPU and display devices</td>
</tr>
<tr>
<td><code>storage</code></td>
<td>Mounting drives and storage devices</td>
</tr>
<tr>
<td><code>network</code></td>
<td>Managing network connections</td>
</tr>
</tbody></table>
<hr />
<h2>DNS Configuration</h2>
<p>When you type <code>google.com</code> in your browser, your system needs to figure out the IP address behind it. This process is called DNS resolution. I have written a blog post about DNS resolution in depth, in case you're interested:</p>
<p><a href="https://blog.sameerbhagtani.dev/dns-resolution-explained">https://blog.sameerbhagtani.dev/dns-resolution-explained</a></p>
<p>Linux handles this in a specific order, and <code>/etc</code> controls that entire pipeline.</p>
<h3><code>/etc/hosts</code></h3>
<p>This is checked before any DNS server is even contacted. It's a simple static lookup table that maps hostnames to IP addresses manually. It looks like:</p>
<pre><code class="language-plaintext">127.0.0.1       localhost
192.168.1.10    myserver.local
</code></pre>
<p>So if you add <code>google.com</code> here pointing to some other IP, your system will use that and never bother asking a DNS server. This is why it's called a local DNS override. Developers use this all the time to point a domain to their local machine for testing.</p>
<h3><code>/etc/resolv.conf</code></h3>
<p>This is where your DNS servers are defined. When <code>/etc/hosts</code> has no answer, your system goes here to find out which DNS server to ask. It looks like:</p>
<pre><code class="language-plaintext">nameserver 8.8.8.8
nameserver 8.8.4.4
</code></pre>
<p>The above example shows Google's DNS severs. You can also use <code>1.1.1.1</code> which is Cloudflare's.</p>
<h3><code>/etc/nsswitch.conf</code></h3>
<p>This is the traffic controller of the whole resolution process. It defines the order in which your system looks things up. The relevant line looks like:</p>
<pre><code class="language-plaintext">hosts: files dns
</code></pre>
<p>This tells the system: first check files (which means <code>/etc/hosts</code>), then go to dns (which means <code>/etc/resolv.conf</code>). This is why <code>/etc/hosts</code> always wins over DNS servers.</p>
<h3>The full DNS resolution flow</h3>
<ol>
<li><p>Check <code>/etc/nsswitch.conf</code> for the lookup order</p>
</li>
<li><p>Check <code>/etc/hosts</code> for a static entry</p>
</li>
<li><p>No match? Go to <code>/etc/resolv.conf</code> for the DNS server</p>
</li>
<li><p>Ask that DNS server for <code>google.com</code></p>
</li>
<li><p>Get the IP back, connect</p>
</li>
</ol>
<hr />
<h2>Network Interface Configuration</h2>
<p>A network interface is your system's way of connecting to a network. It can be physical, like your ethernet port or WiFi card, or virtual, like a loopback interface. Each interface gets a name:</p>
<ul>
<li><p><code>eth0</code> or <code>enp3s0</code>: your ethernet card</p>
</li>
<li><p><code>wlan0</code> or <code>wlp2s0</code>: your WiFi card</p>
</li>
<li><p><code>lo</code>: the loopback interface, always <code>127.0.0.1</code>, used by your system to talk to itself</p>
</li>
</ul>
<p>You can see all your interfaces with:</p>
<pre><code class="language-bash">ip link show
</code></pre>
<p>The location of these network config files varies by distro, which is one of the few places where the FHS does not give you full uniformity.</p>
<p>For Debian and older Ubuntu systems, the file is located at <code>/etc/network/interfaces</code>:</p>
<pre><code class="language-plaintext">auto eth0
iface eth0 inet dhcp
</code></pre>
<p>This says: bring up <code>eth0</code> automatically on boot, and get its IP via DHCP.</p>
<hr />
<h2>Service Configurations</h2>
<p>When you run <code>systemctl start nginx</code> or <code>systemctl enable ssh</code>, systemd needs to know:</p>
<ul>
<li><p>What those services actually are?</p>
</li>
<li><p>How should they start?</p>
</li>
<li><p>What user should run them?</p>
</li>
<li><p>What happens if they crash?</p>
</li>
</ul>
<p>All of this is defined in a unit file.</p>
<p><code>/etc/systemd/system/</code> is where your local unit files live. These are either custom services you created yourself, or overrides to the default unit files that came with installed packages.</p>
<h3>What does a unit file look like?</h3>
<p>Let's look at a simple example. Say you want to create a service that runs a Node.js app on boot:</p>
<pre><code class="language-plaintext">[Unit]
Description=My Node.js App
After=network.target

[Service]
ExecStart=/usr/bin/node /home/sameer/app/index.js
Restart=always
User=sameer
</code></pre>
<p>Breaking down the two sections:</p>
<ul>
<li><p><code>[Unit]</code>: Metadata about the service.</p>
<ul>
<li><code>After=network.target</code>: Don't start this service until the network is up.</li>
</ul>
</li>
<li><p><code>[Service]</code>: The actual behavior</p>
<ul>
<li><p><code>ExecStart</code>: the command to run</p>
</li>
<li><p><code>Restart=always</code>: if the process crashes, restart it automatically</p>
</li>
<li><p><code>User</code>: run the process as this user, not as root</p>
</li>
</ul>
</li>
</ul>
<h3>Enabling vs Starting</h3>
<p>There is an important distinction here that trips up a lot of beginners:</p>
<pre><code class="language-plaintext">systemctl start nginx    # starts the service right now
systemctl enable nginx   # makes it start automatically on every boot
</code></pre>
<p><code>start</code> is temporary. <code>enable</code> is permanent. You almost always want both:</p>
<pre><code class="language-plaintext">systemctl enable --now nginx
</code></pre>
<p>The <code>--now</code> flag starts it immediately and enables it for future boots in one command.</p>
<h3>Where do default unit files live then?</h3>
<p>If <code>/etc/systemd/system/</code> is for local configs, where do the unit files for packages like <code>nginx</code> or <code>ssh</code> live? Those ship to <code>/usr/lib/systemd/system/</code>.</p>
<p>The rule is simple: <code>/etc/systemd/system/</code> always takes priority over <code>/usr/lib/systemd/system/</code>. So if you want to override how a package's service behaves without touching the original file, you drop your version in <code>/etc/systemd/system/</code> and systemd will use that instead.</p>
<hr />
<h2><code>/proc</code>: The Process Filesystem</h2>
<p><code>/proc</code> is one of those things that genuinely makes you stop and think. It looks like a directory full of files, but none of these files actually exist on your disk. There is nothing written to your SSD or HDD here.</p>
<p><code>/proc</code> is a virtual filesystem that the kernel generates in memory, live, every time you look at it.</p>
<p>Think of it as a window into your running kernel. Whatever is happening on your system right now, the kernel is exposing it as readable files inside <code>/proc</code>. The moment a process starts, an entry appears. The moment it dies, it disappears.</p>
<p>You can verify this yourself:</p>
<pre><code class="language-plaintext">ls /proc
</code></pre>
<p>You will see a bunch of numbered directories like <code>1</code>, <code>423</code>, <code>1089</code> and so on. Each number is a PID (Process ID), and each directory contains information about that running process. Open one up:</p>
<pre><code class="language-plaintext">ls /proc/1
</code></pre>
<p>You will find files like <code>status</code>, <code>cmdline</code>, <code>maps</code>, <code>fd</code> and more, all describing exactly what that process is doing right now.</p>
<p>For example:</p>
<pre><code class="language-plaintext">cat /proc/1/status
</code></pre>
<p>This will show you the name of the process, its state, memory usage, which user is running it, and more. All of that, served as a plain text file.</p>
<p>This is the "everything is a file" philosophy at its most elegant. The kernel is not a black box. It is constantly talking to you through <code>/proc</code>, and all you need to read it is <code>cat</code>.</p>
<hr />
<h2>Routing Tables</h2>
<p>When your system wants to send a packet to some IP address, it does not just blindly throw it onto the network. It first consults a routing table, which is essentially a set of rules that answer one question: for this destination, which interface should I use and where should I forward the packet?</p>
<p>A simple way to see your routing table is:</p>
<pre><code class="language-plaintext">ip route show
</code></pre>
<p>You will see something like:</p>
<pre><code class="language-plaintext">default via 192.168.1.1 dev wlan0
192.168.1.0/24 dev wlan0 proto kernel scope link src 192.168.1.105
</code></pre>
<ul>
<li><p>The first line says: for everything else, forward to <code>192.168.1.1</code> (your router) via <code>wlan0</code>.</p>
</li>
<li><p>The second line says: for anything in the <code>192.168.1.0/24</code> range, you can reach it directly through <code>wlan0</code> without going through a gateway.</p>
</li>
</ul>
<p>Now, this same information is also exposed as a file inside <code>/proc</code>:</p>
<pre><code class="language-plaintext">cat /proc/net/route
</code></pre>
<pre><code class="language-plaintext">Iface    Destination  Gateway   Flags  RefCnt  Use  Metric  Mask
wlan0    00000000     0101A8C0  0003   0       0    100     00000000
wlan0    0001A8C0     00000000  0001   0       0    100     00FFFFFF
</code></pre>
<p>This is the raw version of the same routing table, but in hex. The values for Destination, Gateway and Mask are in little endian hex format, which is why <code>0101A8C0</code> translates to <code>192.168.1.1</code>. Not the most human readable format, which is exactly why tools like <code>ip route</code> exist on top of it.</p>
<p>The key insight here is that <code>/proc/net/route</code> is not a config file. You cannot edit it to change your routes. It is purely a read only window into what the kernel currently knows about routing, consistent with the whole philosophy of <code>/proc</code>.</p>
<hr />
<h2>System Logs</h2>
<p>When something goes wrong on your system, the first place you go is <code>/var/log</code>. This is where Linux keeps logs for pretty much everything: the kernel, system services, applications, authentication events, and more.</p>
<pre><code class="language-plaintext">ls /var/log
</code></pre>
<p>You will see a bunch of files and directories. Here are the important ones:</p>
<pre><code class="language-plaintext">/var/log
├── syslog     -&gt; General system activity logs (Debian/Ubuntu)
├── auth.log   -&gt; Authentication events (logins, sudo usage)
├── kern.log   -&gt; Kernel messages
├── dmesg      -&gt; Boot time hardware detection logs
└── journal/   -&gt; systemd's binary log store
</code></pre>
<h3>Reading logs</h3>
<p>For most log files, a simple <code>cat</code> or <code>tail</code> works:</p>
<pre><code class="language-plaintext">tail -f /var/log/auth.log
</code></pre>
<p>The <code>-f</code> flag follows the file in real time, so you can watch events as they come in. Useful for monitoring login attempts or debugging a service.</p>
<p>For systemd based systems, the preferred way to read logs is through <code>journalctl</code>:</p>
<pre><code class="language-plaintext">journalctl -u nginx        # logs for a specific service
journalctl -f              # follow logs in real time
journalctl --since today   # logs from today only
</code></pre>
<h3>What insights do logs actually give you?</h3>
<p>A few practical examples of what you can catch from logs:</p>
<ul>
<li><p>Someone repeatedly trying to SSH into your server with wrong passwords: visible in <code>auth.log</code></p>
</li>
<li><p>A service that keeps crashing on boot: visible in <code>journalctl -u servicename</code></p>
</li>
<li><p>A kernel panic or hardware error: visible in <code>kern.log</code> or <code>dmesg</code></p>
</li>
<li><p>General system misbehavior: visible in <code>syslog</code></p>
</li>
</ul>
<hr />
<h2>File Descriptors</h2>
<p>When a program opens a file, the kernel does not give it direct access to the file. Instead, it gives back a small integer called a file descriptor. This integer is just a reference that the program uses to interact with the file going forward.</p>
<p>Every process gets three file descriptors by default when it starts:</p>
<pre><code class="language-plaintext">0 -&gt; stdin  (standard input)
1 -&gt; stdout (standard output)
2 -&gt; stderr (standard error)
</code></pre>
<p>When the program opens additional files, they get assigned the next available numbers: <code>3</code>, <code>4</code>, <code>5</code> and so on.</p>
<p>You can see the file descriptors of any running process through <code>/proc</code>:</p>
<pre><code class="language-plaintext">ls /proc/&lt;PID&gt;/fd
</code></pre>
<p>This will show you every file, socket, pipe or device that process currently has open, each represented as a numbered symlink.</p>
<h3>Everything is a File Descriptor</h3>
<p>This is where the "everything is a file" philosophy gets very practical. In Linux, file descriptors are not just for files on disk. They represent:</p>
<ul>
<li><p>Regular files</p>
</li>
<li><p>Directories</p>
</li>
<li><p>Network sockets</p>
</li>
<li><p>Pipes between processes</p>
</li>
<li><p>Device files in <code>/dev</code></p>
</li>
</ul>
<p>When your Node.js server accepts an incoming HTTP connection, the kernel hands it a file descriptor for that socket. The server reads from it and writes to it just like a regular file. Same interface, whether it is a text file or a network connection.</p>
<h3>The Default Limit and Why it Matters</h3>
<p>The kernel puts a limit on how many file descriptors a single process can have open at once. You can check yours with:</p>
<pre><code class="language-plaintext">ulimit -n
</code></pre>
<p>On most systems this defaults to <code>1024</code>. This means a single process can have at most 1024 files, sockets, or connections open at the same time.</p>
<p>For a simple script or a CLI tool, 1024 is more than enough. But for a web server or a WebSocket server, this becomes a real problem fast.</p>
<h3>The WebSocket Problem</h3>
<p>A WebSocket server maintains a persistent open connection with every connected client. Each connection is a file descriptor. So if you have 1024 concurrent users connected to your WebSocket server, you have hit the limit. The 1025th user cannot connect. The kernel will throw a <code>Too many open files</code> error and your server will start rejecting connections.</p>
<p>This is not a bug in your code. It is a system level limit you need to raise.</p>
<h3>Raising the Limit</h3>
<p>There are two limits to be aware of:</p>
<pre><code class="language-plaintext">ulimit -n   # soft limit, applies to your current session
</code></pre>
<p>To raise it permanently, you edit <code>/etc/security/limits.conf</code>:</p>
<pre><code class="language-plaintext">*    soft    nofile    65536
*    hard    nofile    65536
</code></pre>
<p>The <code>*</code> applies to all users. <code>nofile</code> stands for number of open files. <code>65536</code> is a common production value for web servers.</p>
<p>For systemd managed services, you set it directly in the unit file instead:</p>
<pre><code class="language-plaintext">[Service]
LimitNOFILE=65536
</code></pre>
<p>After making these changes, restart the service and verify:</p>
<pre><code class="language-plaintext">cat /proc/&lt;PID&gt;/limits
</code></pre>
<p>This is one of the first things you tune when deploying a WebSocket server or any high concurrency application in production. A server with default limits will quietly start failing under load, and the logs will tell you exactly why.</p>
<hr />
<h2>Conclusion</h2>
<p>In the end, the Linux filesystem is far more than a collection of folders. It reflects a philosophy of simplicity, consistency, and treating system resources through one unified interface.</p>
<p>Once you understand what lives where, Linux stops feeling mysterious and starts feeling logical. And as developers, that understanding gives us a real edge when working with servers, debugging production systems, or simply feeling more at home inside the machines that run the modern web.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding this in JavaScript]]></title><description><![CDATA[Introduction
Most JavaScript confusion around this comes from one wrong assumption: that this depends on where a function is defined. It doesn't. It depends on who called the function.
That one shift ]]></description><link>https://blog.sameerbhagtani.dev/understanding-this-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/understanding-this-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[this keyword]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Wed, 15 Apr 2026 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/7ef0acd1-ee62-4af1-beb9-dd9e492e478e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Most JavaScript confusion around <code>this</code> comes from one wrong assumption: that <code>this</code> depends on where a function is defined. It doesn't. It depends on who called the function.</p>
<p>That one shift in thinking makes most of the confusion go away.</p>
<hr />
<h2>What <code>this</code> Actually is</h2>
<p><code>this</code> is a reference to the calling context of a function. When a function runs, JavaScript looks at what triggered the call and sets <code>this</code> to that thing.</p>
<p>Not where the function lives in your file. Not which object it belongs to in your source code. Who called it at runtime.</p>
<hr />
<h2><code>this</code> in the Global Context</h2>
<p>When you call a plain function with nothing owning it, <code>this</code> falls back to the global object.</p>
<pre><code class="language-javascript">function greet() {
    console.log(this);
}

greet();
</code></pre>
<p>In a browser, that logs <code>window</code>. In Node.js, it's <code>global</code>. In strict mode, it's <code>undefined</code>.</p>
<p>Nobody specific called it, so JavaScript picks the default.</p>
<hr />
<h2><code>this</code> Inside an Object</h2>
<p>This is where <code>this</code> starts being useful.</p>
<pre><code class="language-javascript">const person = {
    name: 'Alice',
    greet: function () {
        console.log("Hi, I'm " + this.name);
    }
};

person.greet(); // Hi, I'm Alice
</code></pre>
<p><code>person</code> is calling <code>greet</code>, so <code>this</code> is <code>person</code>. That's it.</p>
<hr />
<h2>How Calling Context Changes <code>this</code></h2>
<p>Here's the part that trips people up. Take the exact same function from above and pull it out of the object:</p>
<pre><code class="language-javascript">const greet = person.greet;
greet(); // Hi, I'm undefined
</code></pre>
<p>Same function. Different caller. Now nobody owns the call, <code>this</code> falls back to the global object, and <code>name</code> isn't defined there.</p>
<p>This is the source of most <code>this</code> bugs. The function didn't change. The calling context did.</p>
<hr />
<h2><code>this</code> Inside Nested Functions</h2>
<p>The problem compounds when you have a function inside a method.</p>
<pre><code class="language-javascript">const person = {
    name: 'Alice',
    greet: function () {
        function inner() {
            console.log(this.name); // undefined
        }
        inner();
    }
};

person.greet();
</code></pre>
<p><code>greet</code> is called by <code>person</code>, so <code>this</code> inside <code>greet</code> is <code>person</code>. But <code>inner</code> is called as a plain function with no owner, so <code>this</code> resets to the global object.</p>
<p>A common fix is to capture <code>this</code> before going in:</p>
<pre><code class="language-javascript">const person = {
    name: 'Alice',
    greet: function () {
        const self = this;
        function inner() {
            console.log(self.name); // Alice
        }
        inner();
    }
};
</code></pre>
<p>Or just use an arrow function, which doesn't have its own <code>this</code> and inherits from the surrounding scope:</p>
<pre><code class="language-javascript">const person = {
    name: 'Alice',
    greet: function () {
        const inner = () =&gt; {
            console.log(this.name); // Alice
        };
        inner();
    }
};
</code></pre>
<hr />
<h2>Arrow Functions Don't Have Their Own <code>this</code></h2>
<p>Arrow functions inherit <code>this</code> from wherever they were defined, and nothing can change that.</p>
<pre><code class="language-javascript">const person = {
    name: 'Alice',
    greet: () =&gt; {
        console.log(this.name); // undefined, always
    }
};

person.greet();
</code></pre>
<p>Even though <code>greet</code> is on <code>person</code>, it's an arrow function. <code>this</code> here is whatever <code>this</code> was in the outer scope when the object was created, not <code>person</code>. Arrow functions are great in a lot of situations, but if you need <code>this</code> to refer to the object, use a regular function.</p>
<hr />
<h2>Summary</h2>
<table>
<thead>
<tr>
<th>Where <code>this</code> appears</th>
<th>What it refers to</th>
</tr>
</thead>
<tbody><tr>
<td>Global function call</td>
<td>Global object (or <code>undefined</code> in strict mode)</td>
</tr>
<tr>
<td>Object method call</td>
<td>The object before the dot</td>
</tr>
<tr>
<td>Nested plain function</td>
<td>Global object (loses the outer <code>this</code>)</td>
</tr>
<tr>
<td>Arrow function</td>
<td>Inherited from surrounding scope</td>
</tr>
</tbody></table>
<hr />
<p>Once you internalize "who called this function," most <code>this</code> surprises stop being surprises. The function is the same. The caller is what changes.</p>
]]></content:encoded></item><item><title><![CDATA[Map and Set in JavaScript: A Practical Guide]]></title><description><![CDATA[Introduction
JavaScript gives you objects and arrays out of the box, and for a long time those two were the default answer to almost every data storage problem. Objects for key-value pairs, arrays for]]></description><link>https://blog.sameerbhagtani.dev/map-and-set-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/map-and-set-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Sets]]></category><category><![CDATA[maps]]></category><category><![CDATA[arrays]]></category><category><![CDATA[Objects]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Thu, 09 Apr 2026 15:23:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/48042771-1825-4fdf-aa99-a361b20a1fb4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>JavaScript gives you objects and arrays out of the box, and for a long time those two were the default answer to almost every data storage problem. Objects for key-value pairs, arrays for lists. Simple enough.</p>
<p>But both come with quirks that can bite you in real code. <code>Map</code> and <code>Set</code> were added in ES6 specifically to address those quirks. They're not replacements, but they solve certain problems cleaner than their older counterparts.</p>
<hr />
<h2>What Is a Map?</h2>
<p>A <code>Map</code> is a collection of key-value pairs, similar to a plain object. The big difference is that a <code>Map</code> accepts any value as a key, not just strings and symbols.</p>
<pre><code class="language-javascript">const map = new Map();

map.set('name', 'Alice');
map.set(42, 'the answer');
map.set({ id: 1 }, 'an object key');

console.log(map.get('name')); // 'Alice'
console.log(map.get(42));     // 'the answer'
console.log(map.size);        // 3
</code></pre>
<p>Maps also maintain insertion order, iterate predictably, and give you a <code>.size</code> property without any tricks.</p>
<hr />
<h2>What Is a Set?</h2>
<p>A <code>Set</code> is a collection of unique values. If you try to add a duplicate, it gets silently ignored. That's pretty much the core feature.</p>
<pre><code class="language-javascript">const set = new Set([1, 2, 3, 2, 1]);

console.log(set.size);          // 3
console.log([...set]);          // [1, 2, 3]

set.add(4);
set.delete(1);
console.log(set.has(1));        // false
console.log(set.has(4));        // true
</code></pre>
<p>Sets also maintain insertion order when you iterate over them.</p>
<hr />
<h2>Map vs Object: Where Objects Fall Short</h2>
<p>Plain objects look like key-value stores, and they mostly work as one. But there are a few real-world gotchas.</p>
<h3>Keys are coerced to strings</h3>
<p>If you use a number or an object as a key on a plain object, JavaScript quietly converts it to a string. That can cause silent bugs.</p>
<pre><code class="language-javascript">const obj = {};
obj[1] = 'one';
obj['1'] = 'overwritten';

console.log(obj[1]); // 'overwritten'
</code></pre>
<p>With a Map, the key <code>1</code> (number) and <code>'1'</code> (string) are different keys.</p>
<h3>Prototype pollution</h3>
<p>A plain object comes with inherited properties from <code>Object.prototype</code>. That's usually harmless, but if you're checking for a key with <code>'toString' in obj</code>, you'll get <code>true</code> even though you never set it.</p>
<h3>No built-in size</h3>
<p>Getting the number of keys in an object means calling <code>Object.keys(obj).length</code>, which creates a temporary array. A Map just has <code>.size</code>.</p>
<p>Here's a side-by-side:</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Object</th>
<th>Map</th>
</tr>
</thead>
<tbody><tr>
<td>Key types</td>
<td>Strings and Symbols only</td>
<td>Any value</td>
</tr>
<tr>
<td>Key ordering</td>
<td>Not guaranteed (mostly)</td>
<td>Insertion order</td>
</tr>
<tr>
<td>Size</td>
<td><code>Object.keys(obj).length</code></td>
<td><code>map.size</code></td>
</tr>
<tr>
<td>Prototype pollution</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Iteration</td>
<td><code>for...in</code>, <code>Object.entries()</code></td>
<td><code>for...of</code>, <code>.forEach()</code></td>
</tr>
</tbody></table>
<ul>
<li><p>Use a plain object for structured data with known string keys, like a config or a DTO.</p>
</li>
<li><p>Use a Map when keys are dynamic, non-string, or when you need reliable iteration and size.</p>
</li>
</ul>
<hr />
<h2>Set vs Array: The Duplicate Problem</h2>
<p>Arrays are ordered and they allow duplicates. That's fine for most things. But if you have a list that should only contain unique values, an array leaves the enforcement to you.</p>
<p>Say you're tracking which user IDs have been processed:</p>
<pre><code class="language-javascript">const processed = [];

function process(id) {
    if (!processed.includes(id)) {
        processed.push(id);
        // do the work
    }
}
</code></pre>
<p>That <code>includes</code> check is O(n). Every call scans the whole array. For small lists it doesn't matter. For large ones it starts to hurt.</p>
<p>With a Set:</p>
<pre><code class="language-javascript">const processed = new Set();

function process(id) {
    if (!processed.has(id)) {
        processed.add(id);
        // do the work
    }
}
</code></pre>
<p><code>.has()</code> on a Set is O(1). The Set also handles the uniqueness guarantee automatically.</p>
<p><strong>Removing duplicates from an array</strong> is another place Sets show up in practice:</p>
<pre><code class="language-javascript">const nums = [1, 2, 2, 3, 4, 3, 5];
const unique = [...new Set(nums)];

console.log(unique); // [1, 2, 3, 4, 5]
</code></pre>
<p>One line. No filter, no reduce, no external library.</p>
<p>The tradeoff: Sets don't have index access. You can't do <code>set[0]</code>. If you need to access items by position, you still need an array.</p>
<table>
<thead>
<tr>
<th>Feature</th>
<th>Array</th>
<th>Set</th>
</tr>
</thead>
<tbody><tr>
<td>Duplicates</td>
<td>Allowed</td>
<td>Not allowed</td>
</tr>
<tr>
<td>Index access</td>
<td>Yes (<code>arr[0]</code>)</td>
<td>No</td>
</tr>
<tr>
<td><code>.has()</code> / <code>.includes()</code></td>
<td>O(n)</td>
<td>O(1)</td>
</tr>
<tr>
<td>Maintaining order</td>
<td>Insertion order</td>
<td>Insertion order</td>
</tr>
<tr>
<td>Iteration</td>
<td>Yes</td>
<td>Yes</td>
</tr>
</tbody></table>
<hr />
<h2>When to Use Map</h2>
<ul>
<li><p>Your keys aren't strings. Numbers, objects, functions as keys all work fine.</p>
</li>
<li><p>You're building a lookup table and need reliable size or iteration.</p>
</li>
<li><p>You're concerned about prototype pollution on a plain object.</p>
</li>
<li><p>You need to delete entries frequently. <code>map.delete(key)</code> is cleaner than <code>delete obj.key</code>.</p>
</li>
</ul>
<p>A practical example: caching computed results by object reference.</p>
<pre><code class="language-javascript">const cache = new Map();

function getLabel(user) {
    if (cache.has(user)) {
        return cache.get(user);
    }
    const label = `\({user.firstName} \){user.lastName}`;
    cache.set(user, label);
    return label;
}
</code></pre>
<p>You can't do that with a plain object. The user object would get coerced to <code>"[object Object]"</code> as a key, and every user would collide.</p>
<hr />
<h2>When to Use Set</h2>
<ul>
<li><p>You need a unique list of anything.</p>
</li>
<li><p>You're doing frequent membership checks on a large collection.</p>
</li>
<li><p>You want to deduplicate an array quickly.</p>
</li>
<li><p>You're tracking "seen" or "visited" states.</p>
</li>
</ul>
<p>Say you're building a tag input where users can add tags to a post, and you want to make sure the same tag can't be added twice:</p>
<pre><code class="language-javascript">const tags = new Set();

tags.add('javascript');
tags.add('webdev');
tags.add('javascript'); // already in there, silently ignored

console.log([...tags]); // ['javascript', 'webdev']
console.log(tags.size); // 2
</code></pre>
<p>No manual duplicate check needed. The Set just handles it.</p>
<hr />
<h2>WeakMap and WeakSet</h2>
<p>JavaScript also has <code>WeakMap</code> and <code>WeakSet</code>. These are similar to <code>Map</code> and <code>Set</code>, but they hold weak references to their keys (WeakMap) or values (WeakSet). That means if the only reference to an object is inside a WeakMap, the garbage collector can still clean it up.</p>
<p>They're useful for attaching private metadata to objects without preventing garbage collection. But they're not iterable and don't have a <code>.size</code>.</p>
<hr />
<h2>Conclusion</h2>
<p><code>Map</code> and <code>Set</code> aren't exotic features. They're practical tools with real performance and correctness benefits over objects and arrays in specific situations. The key is knowing which situation you're in.</p>
<p>If your keys are dynamic or non-string, reach for <code>Map</code>. If your list needs to stay unique or you're checking membership often, reach for <code>Set</code>. Otherwise, objects and arrays are still perfectly fine.</p>
]]></content:encoded></item><item><title><![CDATA[Destructuring in JavaScript: Write Less, Read More]]></title><description><![CDATA[Introduction
Most JavaScript codebases are full of code like this:
const user = { name: "Sara", age: 28, city: "Mumbai" };
const name = user.name;
const age = user.age;
const city = user.city;

Three ]]></description><link>https://blog.sameerbhagtani.dev/destructuring-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/destructuring-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Destructuring]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Thu, 09 Apr 2026 13:12:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/324442d5-1ae1-4710-92f5-8813f2d1dbd7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Most JavaScript codebases are full of code like this:</p>
<pre><code class="language-javascript">const user = { name: "Sara", age: 28, city: "Mumbai" };
const name = user.name;
const age = user.age;
const city = user.city;
</code></pre>
<p>Three separate lines to pull three values out of one object. It works, but it's tedious. Destructuring is the cleaner way to do the same thing.</p>
<hr />
<h2>What Destructuring Actually Means</h2>
<p>Destructuring is a syntax that lets you unpack values from arrays or properties from objects into individual variables, all in one line. The word sounds more complicated than the concept. You're just telling JavaScript: "grab these specific things and give them their own names."</p>
<p>It showed up in ES6 (2015) and has become one of those features you use constantly once you know it.</p>
<hr />
<h2>Destructuring Arrays</h2>
<p>With arrays, destructuring works by position. The first variable gets the first element, the second gets the second, and so on.</p>
<p>Before:</p>
<pre><code class="language-javascript">const colors = ["red", "green", "blue"];
const first = colors[0];
const second = colors[1];
const third = colors[2];
</code></pre>
<p>After:</p>
<pre><code class="language-javascript">const colors = ["red", "green", "blue"];
const [first, second, third] = colors;
</code></pre>
<p>Same result, less noise.</p>
<h3>Skipping Elements</h3>
<p>You can skip positions you don't care about using commas:</p>
<pre><code class="language-javascript">const [, second, , fourth] = [10, 20, 30, 40];
console.log(second); // 20
console.log(fourth); // 40
</code></pre>
<h3>Rest in Arrays</h3>
<p>You can grab the first few items and collect the rest into a new array:</p>
<pre><code class="language-javascript">const [head, ...tail] = [1, 2, 3, 4, 5];
console.log(head); // 1
console.log(tail); // [2, 3, 4, 5]
</code></pre>
<p>The above example makes use of the rest operator. If you do not know about it, checkout this other blog post I wrote on <a href="https://blog.sameerbhagtani.dev/spread-vs-rest-operators-in-javascript">Spread &amp; Rest Operators in JavaScript</a>.</p>
<hr />
<h2>Destructuring Objects</h2>
<p>With objects, you match by property name, not position. The variable name has to match the key you want to extract.</p>
<p>Before:</p>
<pre><code class="language-javascript">const product = { title: "Notebook", price: 120, stock: 50 };
const title = product.title;
const price = product.price;
const stock = product.stock;
</code></pre>
<p>After:</p>
<pre><code class="language-javascript">const { title, price, stock } = product;
</code></pre>
<p>Same three variables, one line.</p>
<h3>Renaming While Destructuring</h3>
<p>If you want a different variable name than the property key:</p>
<pre><code class="language-javascript">const { title: productName, price: cost } = product;
console.log(productName); // "Notebook"
console.log(cost);        // 120
</code></pre>
<p>The syntax reads as "extract <code>title</code>, but call it <code>productName</code>."</p>
<h3>Nested Objects</h3>
<p>Objects inside objects work too, you just nest the destructuring syntax:</p>
<pre><code class="language-javascript">const order = {
    id: 101,
    customer: {
        name: "Raj",
        email: "raj@example.com"
    }
};

const { customer: { name, email } } = order;
console.log(name);  // "Raj"
console.log(email); // "raj@example.com"
</code></pre>
<hr />
<h2>Default Values</h2>
<p>What happens if the property you're trying to extract doesn't exist? Without a default, you get <code>undefined</code>. With a default, you get a fallback.</p>
<pre><code class="language-javascript">const settings = { theme: "dark" };
const { theme, language = "en" } = settings;

console.log(theme);    // "dark"
console.log(language); // "en"
</code></pre>
<p><code>language</code> wasn't in <code>settings</code>, so the default kicked in. This works for arrays too:</p>
<pre><code class="language-javascript">const [a = 0, b = 0] = [5];
console.log(a); // 5
console.log(b); // 0
</code></pre>
<p>Defaults only apply when the value is <code>undefined</code>, not when it's <code>null</code> or <code>0</code> or an empty string.</p>
<hr />
<h2>Where This Shows Up in Real Code</h2>
<h3>Function Parameters</h3>
<p>This is probably the most common use. Instead of pulling properties out at the start of every function:</p>
<pre><code class="language-javascript">// Before
function greet(user) {
    const name = user.name;
    const age = user.age;
    console.log(`\({name} is \){age} years old`);
}

// After
function greet({ name, age }) {
    console.log(`\({name} is \){age} years old`);
}
</code></pre>
<p>The function signature now tells you exactly what it needs. That's a real improvement when you're reading unfamiliar code.</p>
<h3>Swapping Variables</h3>
<p>Without destructuring, swapping two variables needs a temp:</p>
<pre><code class="language-javascript">let x = 1, y = 2;
let temp = x;
x = y;
y = temp;
</code></pre>
<p>With destructuring:</p>
<pre><code class="language-javascript">let x = 1, y = 2;
[x, y] = [y, x];
</code></pre>
<h3>Returning Multiple Values from a Function</h3>
<p>Functions can only return one thing, but that thing can be an array or object. Destructuring makes unpacking the result clean:</p>
<pre><code class="language-javascript">function getMinMax(arr) {
    return { min: Math.min(...arr), max: Math.max(...arr) };
}

const { min, max } = getMinMax([3, 1, 7, 2, 9]);
console.log(min); // 1
console.log(max); // 9
</code></pre>
<hr />
<h2>Why It Matters</h2>
<p>The real benefit isn't that destructuring saves a few lines. It's that code becomes easier to scan. When you see <code>const { name, age } = user</code> at the top of a function, you immediately know what data that function works with. You don't have to trace through <code>user.this</code> and <code>user.that</code> scattered across 20 lines.</p>
<p>It also reduces the chance of typos. Writing <code>user.nmae</code> is easy to miss. Destructuring once at the top and using <code>name</code> everywhere after that gives you one place where a typo can happen instead of many.</p>
<p>That said, don't destructure everything just because you can. For a one-off property access, <code>user.name</code> is perfectly readable. Destructuring earns its place when you're using multiple properties, passing them into functions, or cleaning up function parameters.</p>
]]></content:encoded></item><item><title><![CDATA[Error Handling in JavaScript: Try, Catch, Finally]]></title><description><![CDATA[Introduction
You write some code. It looks right. You run it, and instead of the output you expected, the browser throws a red wall of text and the whole script stops dead. That's a runtime error, and]]></description><link>https://blog.sameerbhagtani.dev/error-handling-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/error-handling-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[exceptionhandling]]></category><category><![CDATA[try-catch-finally]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Thu, 09 Apr 2026 08:42:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/13b33deb-a16e-4e6c-9980-96dbb800b2e9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>You write some code. It looks right. You run it, and instead of the output you expected, the browser throws a red wall of text and the whole script stops dead. That's a runtime error, and if you haven't planned for it, your user just saw a broken page.</p>
<p>JavaScript has a structured way to handle this: the <code>try...catch...finally</code> block. It's not glamorous, but understanding it properly will save you a lot of late-night debugging.</p>
<hr />
<h2>What Errors Actually Are</h2>
<p>JavaScript has several built-in error types. You'll run into these most often:</p>
<ul>
<li><p><code>ReferenceError</code>: accessing a variable that doesn't exist</p>
</li>
<li><p><code>TypeError</code>: calling something that isn't a function, or reading a property off <code>null</code></p>
</li>
<li><p><code>SyntaxError</code>: malformed code (usually caught before runtime)</p>
</li>
<li><p><code>RangeError</code>: a value that falls outside an allowed range</p>
</li>
</ul>
<p>Here's a classic example:</p>
<pre><code class="language-javascript">const user = null;
console.log(user.name); // TypeError: Cannot read properties of null
</code></pre>
<p>JavaScript tries to access <code>.name</code> on <code>null</code>, fails, and throws an error. Without any handling, execution stops right there. Everything below that line never runs.</p>
<hr />
<h2>The try and catch Blocks</h2>
<p>The <code>try</code> block wraps code that might fail. If it does, execution jumps to <code>catch</code>, which receives the error as an argument.</p>
<pre><code class="language-javascript">try {
    const user = null;
    console.log(user.name);
} catch (error) {
    console.log("Something went wrong:", error.message);
}
</code></pre>
<p>The script no longer crashes. Instead of a red wall of text, you get a controlled message. That's what "graceful failure" means in practice. Not pretending errors don't happen, just deciding what to do when they do.</p>
<p>The <code>error</code> object has a few useful properties:</p>
<ul>
<li><p><code>error.message</code>: a human-readable description</p>
</li>
<li><p><code>error.name</code>: the type of error (<code>"TypeError"</code>, <code>"ReferenceError"</code>, etc.)</p>
</li>
<li><p><code>error.stack</code>: the full call stack, useful for debugging</p>
</li>
</ul>
<p>Getting into the habit of logging <code>error.stack</code> (not just <code>error.message</code>) during development will show you exactly where things went wrong, including the file and line number.</p>
<hr />
<h2>The finally Block</h2>
<p><code>finally</code> runs no matter what, whether the <code>try</code> block succeeded, threw an error, or even hit a <code>return</code> statement.</p>
<pre><code class="language-javascript">function fetchData() {
    try {
        // simulate a risky operation
        const data = JSON.parse("invalid json {{{");
        return data;
    } catch (error) {
        console.log("Failed to parse:", error.message);
    } finally {
        console.log("Cleanup done.");
    }
}
</code></pre>
<p>The <code>finally</code> block is where you put cleanup code: closing a database connection, hiding a loading spinner, releasing a lock. Stuff that needs to happen regardless of whether the operation worked.</p>
<p>A common real-world pattern looks like this:</p>
<pre><code class="language-javascript">async function loadUser(id) {
    showSpinner(true);
    try {
        const response = await fetch(`/api/users/${id}`);
        const user = await response.json();
        renderUser(user);
    } catch (error) {
        showErrorMessage("Could not load user.");
    } finally {
        showSpinner(false);
    }
}
</code></pre>
<p>The spinner always gets hidden. It doesn't matter if the fetch succeeded or failed. Without <code>finally</code>, you'd need to call <code>showSpinner(false)</code> in both the <code>try</code> and the <code>catch</code>, and you'd inevitably miss a case.</p>
<hr />
<h2>Throwing Custom Errors</h2>
<p>JavaScript lets you throw your own errors with the <code>throw</code> keyword. You can throw a string, a number, or an object, but the cleanest approach is to throw an actual <code>Error</code> instance so you get a stack trace.</p>
<pre><code class="language-javascript">function divide(a, b) {
    if (b === 0) {
        throw new Error("Division by zero is not allowed.");
    }
    return a / b;
}

try {
    const result = divide(10, 0);
} catch (error) {
    console.log(error.message); // "Division by zero is not allowed."
}
</code></pre>
<p>You can also extend the built-in <code>Error</code> class to create named custom errors. This is useful when you want to handle different error types differently:</p>
<pre><code class="language-javascript">class ValidationError extends Error {
    constructor(message) {
        super(message);
        this.name = "ValidationError";
    }
}

function validateAge(age) {
    if (typeof age !== "number") {
        throw new ValidationError("Age must be a number.");
    }
    if (age &lt; 0 || age &gt; 120) {
        throw new ValidationError("Age must be between 0 and 120.");
    }
}

try {
    validateAge("twenty");
} catch (error) {
    if (error instanceof ValidationError) {
        console.log("Validation failed:", error.message);
    } else {
        throw error; // re-throw unexpected errors
    }
}
</code></pre>
<p>Notice the re-throw at the end. If the error isn't a <code>ValidationError</code>, you probably don't know how to handle it, so let it bubble up. Swallowing all errors silently is one of the more frustrating bugs to track down, because nothing tells you something went wrong.</p>
<hr />
<h2>Why Error Handling Matters</h2>
<p>There are three practical reasons to get this right.</p>
<h3>Your users get a better experience</h3>
<p>A caught error can show a friendly message or a fallback UI. An uncaught one shows nothing, or breaks the page mid-render.</p>
<h3>Debugging gets easier</h3>
<p>When you log errors consistently, you build a trail. Adding something like <code>console.error(error.stack)</code> in your catch blocks gives you a line number and a call path, not just a vague failure.</p>
<h3>Your app keeps running</h3>
<p>An unhandled error in one place can cascade and break unrelated parts of the page. Containing it means the rest of your code still works.</p>
<h2>Handling Async Err</h2>
<p>One thing worth knowing: <code>try...catch</code> only catches synchronous errors by default. For async code, you need to use it inside an <code>async</code> function with <code>await</code>, or chain <code>.catch()</code> on a promise. Forgetting this is a common source of "my error handler isn't catching anything" confusion.</p>
<pre><code class="language-javascript">// This does NOT catch the rejection:
try {
    fetch("/api/data"); // not awaited
} catch (error) {
    console.log("This never runs");
}

// This DOES:
try {
    const response = await fetch("/api/data");
} catch (error) {
    console.log("Network error:", error.message);
}
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>Error handling isn't about anticipating every possible failure. It's about deciding, ahead of time, what your code should do when something goes wrong. The <code>try</code> block says "try this." The <code>catch</code> block says "if it breaks, do this instead." The <code>finally</code> block says "either way, do this."</p>
<p>That structure alone handles most of the cases you'll encounter. Custom errors and re-throwing handle the rest.</p>
]]></content:encoded></item><item><title><![CDATA[JavaScript Modules: Import and Export Explained]]></title><description><![CDATA[Introduction
Picture a codebase from five years ago. One file. Maybe two. A couple of <script> tags in your HTML, a few functions at the top, and a pile of variables that you promised yourself you'd c]]></description><link>https://blog.sameerbhagtani.dev/javascript-modules-import-export-explained</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/javascript-modules-import-export-explained</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[modules]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Sun, 05 Apr 2026 06:23:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/dac665b6-75bb-4676-9eb2-274fdec4c7c7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Picture a codebase from five years ago. One file. Maybe two. A couple of <code>&lt;script&gt;</code> tags in your HTML, a few functions at the top, and a pile of variables that you promised yourself you'd clean up later. It worked. Sort of.</p>
<p>Then the project grew. More features, more functions, more developers. That one file ballooned into 2,000 lines. Scroll to find anything. Step over someone else's variable that happens to share the name you chose. Break three things trying to fix one. Sound familiar?</p>
<p>This is the problem JavaScript modules were built to solve.</p>
<hr />
<h2>The Mess Before Modules</h2>
<p>In the early days, JavaScript had no native way to split code across files cleanly. Everything loaded into one global scope. If you had a <code>utils.js</code> and an <code>app.js</code>, both loaded via <code>&lt;script&gt;</code> tags, every variable and function from both files lived in the same space. Name a function <code>formatDate</code> in two files? One of them would silently overwrite the other. You would not get an error. You would just get the wrong output at the worst possible time.</p>
<p>Developers worked around this using patterns like IIFEs (immediately invoked function expressions) to create private scopes, or namespace objects to avoid collisions. These helped, but they were workarounds, not solutions. The code was harder to read, harder to share, and nearly impossible to test in isolation.</p>
<p>Modules changed that. A module is just a file with its own scope. Variables inside it do not leak out unless you explicitly say so. You choose what to expose and what to keep private. You decide what to pull in from elsewhere.</p>
<hr />
<h2>Exporting: Making Things Available</h2>
<p>When you write a module, nothing in it is accessible from the outside by default. You have to export it.</p>
<p>There are two ways to do that: named exports and a default export.</p>
<h3>Named Exports</h3>
<p>Named exports let you expose multiple things from a single file. You attach the <code>export</code> keyword to whatever you want to share.</p>
<pre><code class="language-javascript">// math.js
export function add(a, b) {
    return a + b;
}

export function subtract(a, b) {
    return a - b;
}

export const PI = 3.14159;
</code></pre>
<p>Each of those three things is now available to other files, but under their exact names.</p>
<p>You can also export them all at the bottom in one shot:</p>
<pre><code class="language-javascript">// math.js
function add(a, b) {
    return a + b;
}

function subtract(a, b) {
    return a - b;
}

const PI = 3.14159;

export { add, subtract, PI };
</code></pre>
<p>Same result. Some people find it cleaner to keep the exports at the bottom, since you can see what a file exposes without reading through all the implementation details.</p>
<h3>Default Exports</h3>
<p>A default export is for when a file represents one main thing. A class, a component, a primary function.</p>
<pre><code class="language-javascript">// greet.js
export default function greet(name) {
    return `Hello, ${name}`;
}
</code></pre>
<p>Each file can have only one default export. That's intentional. If you're exporting more than one main thing, named exports are probably the better fit.</p>
<hr />
<h2>Importing: Pulling It In</h2>
<p>Once something is exported, you can import it from another file using the <code>import</code> statement.</p>
<h3>Importing Named Exports</h3>
<pre><code class="language-javascript">// app.js
import { add, PI } from './math.js';

console.log(add(2, 3));    // 5
console.log(PI);           // 3.14159
</code></pre>
<p>The curly braces are not optional here. The name inside must match exactly what was exported. This is the module system enforcing the contract between files: you exported <code>add</code>, so you import <code>add</code>.</p>
<p>If the name conflicts with something already in your file, you can rename it on the way in:</p>
<pre><code class="language-javascript">import { add as sum } from './math.js';
console.log(sum(2, 3)); // 5
</code></pre>
<h3>Importing a Default Export</h3>
<p>Default exports skip the curly braces, and you can name them whatever you want on the import side:</p>
<pre><code class="language-javascript">// app.js
import greet from './greet.js';
console.log(greet('Sara')); // Hello, Sara
</code></pre>
<p>Because there's only one default per file, there's no ambiguity about what you're getting. The name <code>greet</code> here is just a local label.</p>
<h3>Mixing Default and Named</h3>
<p>A file can have both. A React component file is a common example:</p>
<pre><code class="language-javascript">// Button.js
export default function Button({ label }) {
    return `&lt;button&gt;${label}&lt;/button&gt;`;
}

export const BUTTON_SIZES = ['sm', 'md', 'lg'];
</code></pre>
<p>And you import them together:</p>
<pre><code class="language-javascript">import Button, { BUTTON_SIZES } from './Button.js';
</code></pre>
<hr />
<h2>Default vs Named: When to Use Which</h2>
<p>Use a <strong>default export</strong> when a file has one clear purpose: a single component, a single class, a single utility function that the file is named after. The file and the export are the same thing.</p>
<p>Use <strong>named exports</strong> when a file is a collection: a set of helper functions, a set of constants, a utilities module. Multiple things live there, and callers should be specific about what they need.</p>
<p>A common mistake is defaulting to default exports everywhere just because it feels simpler. It starts to hurt when you're trying to search for where something is defined. Named imports make that easy because the name is consistent across every file that uses it. With default imports, every file can invent its own name.</p>
<hr />
<h2>Why Modular Code Is Worth the Setup</h2>
<p>Breaking your code into modules does more than just prevent naming collisions.</p>
<p>Each module has a clear responsibility. When something breaks in <code>formatDate</code>, you know to look in <code>dateUtils.js</code>, not scroll through a 3,000-line file hoping the relevant code is somewhere in the middle.</p>
<p>Modules are testable in isolation. You can import a single function, write tests for it, and run them without loading the entire application.</p>
<p>Modules make collaboration easier. Two developers can work in different files without stepping on each other constantly. Merge conflicts shrink. Code reviews get smaller.</p>
<p>Unused code gets easier to find and delete. If nothing imports from a file, that file is dead weight. That's much harder to see when everything is tangled together.</p>
<hr />
<h2>Conclusion</h2>
<p>Think of a module like a toolbox. You build it, you put tools inside, and you lock it. Nobody can reach in and grab something unless you've left it on the counter (exported it). And when another person needs a specific tool, they have to ask for it by name (import it). No rummaging around. No accidentally grabbing the wrong thing.</p>
<p>That discipline is what makes large codebases navigable. Not clever tricks. Just clear boundaries, consistently applied.</p>
<p>Once you get used to writing code this way, going back to the global-everything approach feels genuinely uncomfortable. Which is probably the point.</p>
]]></content:encoded></item><item><title><![CDATA[Array Flatten in JavaScript: Every Approach You Need to Know]]></title><description><![CDATA[Introduction
If you've worked with data coming from an API or built any kind of recursive data structure, you've probably run into nested arrays. They show up everywhere. And at some point, you need t]]></description><link>https://blog.sameerbhagtani.dev/array-flatten-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/array-flatten-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[array]]></category><category><![CDATA[flatten array]]></category><category><![CDATA[interview]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Sun, 05 Apr 2026 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/0481abaf-c344-4074-84a3-ebe753f31ac1.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've worked with data coming from an API or built any kind of recursive data structure, you've probably run into nested arrays. They show up everywhere. And at some point, you need to turn that messy structure into something flat and workable.</p>
<p>This post covers what nested arrays are, why you'd want to flatten them, and the different ways to do it in JavaScript, including what interviewers actually expect you to know.</p>
<hr />
<h2>What Are Nested Arrays?</h2>
<p>A nested array is just an array that contains other arrays as elements.</p>
<pre><code class="language-javascript">// One level of nesting
const arr = [1, [2, 3], [4, 5]];

// Multiple levels
const deep = [1, [2, [3, [4, [5]]]]];

// Mixed nesting
const mixed = [1, [2, 3], [4, [5, 6]], 7];
</code></pre>
<p>Think of it like folders inside folders. The outer array is your root folder. Each inner array is a subfolder. Flattening means pulling everything out into one single folder.</p>
<pre><code class="language-javascript">// Before flattening
[1, [2, 3], [4, [5, 6]]]

// After flattening (one level)
[1, 2, 3, 4, [5, 6]]

// After full flattening
[1, 2, 3, 4, 5, 6]
</code></pre>
<hr />
<h2>Why Flattening Matters</h2>
<p>The most common reason is data normalization. You get a response from an API where each item contains a list of sub-items, and you need one unified list to map over, filter, or pass into something else.</p>
<p>Other real scenarios:</p>
<ul>
<li><p>Collecting results from multiple paginated responses into one array</p>
</li>
<li><p>Flattening a matrix (2D array) into a 1D array for computation</p>
</li>
<li><p>Processing tree-like structures like category hierarchies or comment threads</p>
</li>
<li><p>Simplifying recursive data before display</p>
</li>
</ul>
<p>The practical upside is that flat arrays are easier to work with. Searching, sorting, and mapping over <code>[1, 2, 3, 4]</code> is a lot simpler than doing the same on <code>[1, [2, [3, 4]]]</code>.</p>
<hr />
<h2>Approach 1: The Native <code>flat()</code> Method</h2>
<p>JavaScript added <code>Array.prototype.flat()</code> in ES2019. It's the clearest option if you don't need to support old environments.</p>
<pre><code class="language-javascript">const arr = [1, [2, 3], [4, [5, 6]]];

arr.flat();     // [1, 2, 3, 4, [5, 6]]  -- one level deep
arr.flat(2);    // [1, 2, 3, 4, 5, 6]   -- two levels deep
arr.flat(Infinity); // fully flattens regardless of depth
</code></pre>
<p><code>flat()</code> takes a depth argument. The default is <code>1</code>. Pass <code>Infinity</code> if you want to flatten everything no matter how deep the nesting goes.</p>
<p>Step by step for <code>arr.flat()</code>:</p>
<ol>
<li><p>It iterates each element</p>
</li>
<li><p>If the element is an array, it spreads its contents one level up</p>
</li>
<li><p>Non-array elements stay as-is</p>
</li>
</ol>
<p>Simple. Use this when you can.</p>
<hr />
<h2>Approach 2: <code>reduce()</code> + <code>concat()</code></h2>
<p>Before <code>flat()</code> existed, this was a common one-liner for shallow flattening:</p>
<pre><code class="language-javascript">const arr = [1, [2, 3], [4, 5]];

const flat = arr.reduce((acc, val) =&gt; acc.concat(val), []);
// [1, 2, 3, 4, 5]
</code></pre>
<p>What's happening here:</p>
<ul>
<li><p>Start with an empty accumulator <code>[]</code></p>
</li>
<li><p>For each element, <code>concat</code> it onto the accumulator</p>
</li>
<li><p><code>concat</code> automatically unwraps one level of array</p>
</li>
</ul>
<p>This only works for one level of nesting. If <code>val</code> is <code>[4, [5]]</code>, you get <code>[1, 2, 3, 4, [5]]</code>, not <code>[1, 2, 3, 4, 5]</code>.</p>
<hr />
<h2>Approach 3: Recursion</h2>
<p>When you need to flatten arrays of arbitrary depth and can't use <code>flat(Infinity)</code>, recursion is the clean mental model.</p>
<pre><code class="language-javascript">function flatten(arr) {
    return arr.reduce((acc, val) =&gt; {
        if (Array.isArray(val)) {
            return acc.concat(flatten(val));
        }
        return acc.concat(val);
    }, []);
}

flatten([1, [2, [3, [4]]]]); // [1, 2, 3, 4]
</code></pre>
<p>Walking through this with <code>[1, [2, [3]]]</code>:</p>
<ol>
<li><p>Element <code>1</code> is not an array, push it: <code>[1]</code></p>
</li>
<li><p>Element <code>[2, [3]]</code> is an array, recurse into it</p>
<ul>
<li><p>Element <code>2</code> is not an array, push it: <code>[2]</code></p>
</li>
<li><p>Element <code>[3]</code> is an array, recurse into it</p>
<ul>
<li>Element <code>3</code> is not an array, push it: <code>[3]</code></li>
</ul>
</li>
</ul>
</li>
<li><p>Concat everything back up: <code>[1, 2, 3]</code></p>
</li>
</ol>
<hr />
<h2>Approach 4: Stack-Based Iterative Flattening</h2>
<p>Recursion works, but for very deeply nested arrays you can hit the call stack limit. An iterative approach using a stack avoids that:</p>
<pre><code class="language-javascript">function flattenIterative(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>How this works:</p>
<ol>
<li><p>Push all elements onto a stack</p>
</li>
<li><p>Pop the top item</p>
</li>
<li><p>If it's an array, spread its contents back onto the stack</p>
</li>
<li><p>If it's a value, add it to the result</p>
</li>
<li><p>Repeat until the stack is empty</p>
</li>
<li><p>Reverse at the end because you were popping (LIFO order)</p>
</li>
</ol>
<p>This handles deeply nested structures without blowing the stack.</p>
<hr />
<h2>Common Interview Scenarios</h2>
<h3>"Implement <code>flat()</code> from scratch"</h3>
<p>This is asking for the recursive approach. Write it using <code>reduce</code> and <code>Array.isArray</code>. Show that you understand the base case (non-array element) and the recursive case (array element).</p>
<h3>"Flatten to a specific depth"</h3>
<p>Add a <code>depth</code> parameter to your recursive function:</p>
<pre><code class="language-javascript">function flatten(arr, depth = 1) {
    return arr.reduce((acc, val) =&gt; {
        if (Array.isArray(val) &amp;&amp; depth &gt; 0) {
            return acc.concat(flatten(val, depth - 1));
        }
        return acc.concat(val);
    }, []);
}

flatten([1, [2, [3, [4]]]], 2); // [1, 2, 3, [4]]
</code></pre>
<p>Each recursive call decrements <code>depth</code>. When it hits 0, stop flattening.</p>
<h3>"What if the array is deeply nested and performance matters?"</h3>
<p>This is where the iterative stack-based approach comes up. Mention that deep recursion risks a stack overflow and that the iterative version handles that.</p>
<h3>"What's the time complexity?"</h3>
<p>For any correct flatten, it's O(n) where n is the total number of elements across all levels. You visit each element exactly once.</p>
<hr />
<h2>Summary</h2>
<table>
<thead>
<tr>
<th>Approach</th>
<th>Use When</th>
</tr>
</thead>
<tbody><tr>
<td><code>flat(Infinity)</code></td>
<td>You need something that just works and env supports it</td>
</tr>
<tr>
<td><code>reduce + concat</code></td>
<td>One level only, simple case</td>
</tr>
<tr>
<td>Recursive <code>flatten()</code></td>
<td>Interview, custom depth control, readable code</td>
</tr>
<tr>
<td>Iterative (stack)</td>
<td>Very deep nesting, performance-sensitive</td>
</tr>
</tbody></table>
<hr />
<h2>Conclusion</h2>
<p>The built-in <code>flat()</code> covers most real-world cases. Understanding the recursive approach is what most interviews actually test. And if you can explain why the iterative version exists, that's usually the thing that moves you from "knows the API" to "understands what's happening under the hood."</p>
]]></content:encoded></item><item><title><![CDATA[Spread vs Rest Operators in JavaScript]]></title><description><![CDATA[Introduction
JavaScript's Spread & Rest Operator look identical. Both are three dots (...). But they do opposite things depending on where you put them.
One expands values out. The other collects valu]]></description><link>https://blog.sameerbhagtani.dev/spread-vs-rest-operators-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/spread-vs-rest-operators-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Spread operator]]></category><category><![CDATA[Rest operator]]></category><category><![CDATA[Operators]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Thu, 02 Apr 2026 03:30:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/340725cd-5f32-46bd-893c-48c544fa81dc.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>JavaScript's Spread &amp; Rest Operator look identical. Both are three dots (<code>...</code>). But they do opposite things depending on where you put them.</p>
<p>One expands values out. The other collects values in. Once that clicks, the rest is just syntax.</p>
<hr />
<h2>What the Spread Operator Does</h2>
<p>The spread operator takes something iterable, like an array or object, and unpacks its contents into individual elements.</p>
<p>Think of it like opening a box and laying everything out on the table.</p>
<pre><code class="language-javascript">const fruits = ['apple', 'banana', 'mango'];
console.log(...fruits); // apple banana mango
</code></pre>
<p>That's useful, but the real power shows up when you're building new arrays or objects.</p>
<pre><code class="language-javascript">const first = [1, 2, 3];
const second = [4, 5, 6];
const combined = [...first, ...second];
// [1, 2, 3, 4, 5, 6]
</code></pre>
<p>No <code>concat</code>. No loops. You just spread both arrays into a new one.</p>
<hr />
<h2>What the Rest Operator Does</h2>
<p>Rest does the reverse. Instead of expanding values, it collects multiple values into a single array.</p>
<p>It's most useful in function parameters when you don't know how many arguments are coming in.</p>
<pre><code class="language-javascript">function sum(...numbers) {
    return numbers.reduce((total, n) =&gt; total + n, 0);
}

sum(1, 2, 3);        // 6
sum(10, 20, 30, 40); // 100
</code></pre>
<p>Here, <code>...numbers</code> gathers every argument into an array. You're not unpacking anything. You're bundling things up.</p>
<hr />
<h2>The Core Difference</h2>
<table>
<thead>
<tr>
<th></th>
<th>Spread</th>
<th>Rest</th>
</tr>
</thead>
<tbody><tr>
<td>What it does</td>
<td>Expands an iterable into individual values</td>
<td>Collects individual values into an array</td>
</tr>
<tr>
<td>Where it's used</td>
<td>Array/object literals, function calls</td>
<td>Function parameter lists</td>
</tr>
<tr>
<td>Direction</td>
<td>Out (unpacking)</td>
<td>In (bundling)</td>
</tr>
</tbody></table>
<p>A quick way to remember: if the <code>...</code> is on the right side of an assignment or inside a function call, it's spread. If it's in the function definition's parameter list, it's rest.</p>
<hr />
<h2>Using Spread with Arrays</h2>
<h3>Copying an array</h3>
<pre><code class="language-javascript">const original = [1, 2, 3];
const copy = [...original];
copy.push(4);

console.log(original); // [1, 2, 3]
console.log(copy);     // [1, 2, 3, 4]
</code></pre>
<p>This gives you a shallow copy. Mutating <code>copy</code> won't touch <code>original</code>. That said, if the array contains objects, those objects are still shared by reference.</p>
<h3>Inserting values while merging</h3>
<pre><code class="language-javascript">const start = [1, 2];
const end = [5, 6];
const full = [...start, 3, 4, ...end];
// [1, 2, 3, 4, 5, 6]
</code></pre>
<p>You can drop values in between spreads. That's something <code>concat</code> can't do as cleanly.</p>
<h3>Passing array items as function arguments</h3>
<pre><code class="language-javascript">const nums = [3, 1, 4, 1, 5];
const max = Math.max(...nums); // 5
</code></pre>
<p><code>Math.max</code> expects individual arguments, not an array. Spread bridges that gap without needing <code>.apply()</code>.</p>
<hr />
<h2>Using Spread with Objects</h2>
<p>Spread works on objects too. It copies key-value pairs into a new object.</p>
<pre><code class="language-javascript">const defaults = { theme: 'light', lang: 'en' };
const userPrefs = { lang: 'fr', fontSize: 14 };

const settings = { ...defaults, ...userPrefs };
// { theme: 'light', lang: 'fr', fontSize: 14 }
</code></pre>
<p>When keys overlap, the last one wins. Here, <code>lang</code> from <code>userPrefs</code> overwrites the one from <code>defaults</code>.</p>
<p>This pattern shows up constantly in config merging, Redux reducers, and anywhere you're building objects from multiple sources.</p>
<hr />
<h2>Practical Use Cases</h2>
<h3>Removing a property from an object</h3>
<pre><code class="language-javascript">const user = { id: 1, name: 'Sara', password: 'secret' };
const { password, ...safeUser } = user;

console.log(safeUser); // { id: 1, name: 'Sara' }
</code></pre>
<p>Here rest is used in destructuring. You pull out the property you don't want, and everything else goes into <code>safeUser</code>.</p>
<h3>Handling variable function arguments</h3>
<pre><code class="language-javascript">function log(level, ...messages) {
    messages.forEach(msg =&gt; console.log(`[${level}]`, msg));
}

log('INFO', 'Server started', 'Listening on port 3000');
// [INFO] Server started
// [INFO] Listening on port 3000
</code></pre>
<p>The first argument is captured separately. Everything after goes into the rest array.</p>
<h3>Adding or overriding properties without mutation</h3>
<pre><code class="language-javascript">const state = { count: 0, loading: false };

const nextState = { ...state, count: state.count + 1 };
// { count: 1, loading: false }
</code></pre>
<p>You get a new object. The original is untouched. This is the standard way to handle state updates in React without mutating directly.</p>
<h3>Cloning and extending arrays</h3>
<pre><code class="language-javascript">const base = ['read', 'write'];
const extended = [...base, 'execute'];
// ['read', 'write', 'execute']
</code></pre>
<p>Useful when building permission sets or option lists that inherit from a base.</p>
<hr />
<h2>A Note on Shallow Copies</h2>
<p>Both spread and rest create shallow copies. For arrays and objects of primitives, that's fine. But if your data is nested, you'll need something deeper, like <code>structuredClone</code>, for full isolation.</p>
<pre><code class="language-javascript">const nested = { a: { b: 1 } };
const copy = { ...nested };

copy.a.b = 99;
console.log(nested.a.b); // 99 (shared reference)
</code></pre>
<p>This trips people up. When you need a fully independent copy, use <code>structuredClone</code>. It recursively clones the entire structure, so nothing is shared.</p>
<pre><code class="language-javascript">const nested = { a: { b: 1 } };
const clone = structuredClone(nested);

clone.a.b = 99;
console.log(nested.a.b); // 1 (untouched)
</code></pre>
<p><code>structuredClone</code> is built into modern browsers and Node.js 17+, so no library needed. For deeply nested data, it's the cleaner option over spread.</p>
<hr />
<h2>Conclusion</h2>
<p>The same three dots, two different jobs. Spread unpacks. Rest collects. Once you see that pattern, you'll start noticing it everywhere, and using it without thinking twice.</p>
]]></content:encoded></item><item><title><![CDATA[Template Literals in JavaScript: Write Cleaner Strings]]></title><description><![CDATA[Introduction
String handling in JavaScript used to be one of those things you just accepted as annoying. You had + operators scattered everywhere, escaped quotes inside quotes, and multi-line strings ]]></description><link>https://blog.sameerbhagtani.dev/template-literals-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/template-literals-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Strings]]></category><category><![CDATA[template literals]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Wed, 01 Apr 2026 03:33:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/710e292a-029c-4f09-968b-a2404f093111.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>String handling in JavaScript used to be one of those things you just accepted as annoying. You had <code>+</code> operators scattered everywhere, escaped quotes inside quotes, and multi-line strings that looked like someone had an argument with their keyboard. Then ES6 came along and fixed most of it in one go.</p>
<hr />
<h2>The Problem With Old-School Concatenation</h2>
<p>Here is a typical piece of pre-ES6 code that builds a greeting:</p>
<pre><code class="language-javascript">var name = "Priya";
var age = 28;
var city = "Mumbai";

var message = "Hello, my name is " + name + ". I am " + age + " years old and I live in " + city + ".";
</code></pre>
<p>It works. It also looks like you assembled it with scotch tape. Every string segment needs its own quote pair, and every variable needs its own <code>+</code> on each side. Miss one space and you get <code>"I am28years old"</code>. Add a variable mid-sentence and you are counting plus signs to make sure you have the right number.</p>
<p>Multi-line strings were worse:</p>
<pre><code class="language-javascript">var html = "&lt;div class='card'&gt;" +
    "&lt;h2&gt;" + title + "&lt;/h2&gt;" +
    "&lt;p&gt;" + description + "&lt;/p&gt;" +
    "&lt;/div&gt;";
</code></pre>
<p>This is technically fine but reading it is a chore. You have to mentally strip the quotes and plus signs to understand the actual structure.</p>
<hr />
<h2>Template Literal Syntax</h2>
<p>Template literals use backticks instead of single or double quotes:</p>
<pre><code class="language-javascript">const greeting = `Hello, world`;
</code></pre>
<p>That alone changes nothing. The power comes from two features built on top of that syntax: interpolation and native multi-line support.</p>
<hr />
<h2>Embedding Variables Directly in Strings</h2>
<p>Inside a template literal, you can drop any JavaScript expression directly into the string using <code>${}</code>:</p>
<pre><code class="language-javascript">const name = "Priya";
const age = 28;
const city = "Mumbai";

const message = `Hello, my name is \({name}. I am \){age} years old and I live in ${city}.`;
</code></pre>
<p>The string reads exactly like it will appear at runtime. No plus signs, no closing and reopening quotes. You just write the sentence and put variables where they belong.</p>
<p>The <code>${}</code> syntax accepts any valid JavaScript expression, not just variables:</p>
<pre><code class="language-javascript">const price = 450;
const quantity = 3;

console.log(`Total: ${price * quantity} rupees`);
// Total: 1350 rupees
</code></pre>
<pre><code class="language-javascript">const user = { name: "Arjun", role: "admin" };

console.log(`Welcome, \({user.name}. Your role is \){user.role}.`);
// Welcome, Arjun. Your role is admin.
</code></pre>
<pre><code class="language-javascript">const score = 72;

console.log(`Result: ${score &gt;= 60 ? "Pass" : "Fail"}`);
// Result: Pass
</code></pre>
<p>Ternaries, method calls, object properties, arithmetic, all of it works inside <code>${}</code> without any extra setup.</p>
<hr />
<h2>Multi-Line Strings Without the Mess</h2>
<p>With regular strings, a newline inside quotes is a syntax error. The old workaround was <code>\n</code> or concatenating across lines:</p>
<pre><code class="language-javascript">// Old way
var poem = "Line one\n" +
    "Line two\n" +
    "Line three";
</code></pre>
<p>Template literals preserve whitespace and line breaks naturally:</p>
<pre><code class="language-javascript">const poem = `Line one
Line two
Line three`;
</code></pre>
<p>What you type is what you get. This makes building HTML fragments or multi-line output much more readable:</p>
<pre><code class="language-javascript">const card = `
    &lt;div class="card"&gt;
        &lt;h2&gt;${title}&lt;/h2&gt;
        &lt;p&gt;${description}&lt;/p&gt;
        &lt;span class="tag"&gt;${category}&lt;/span&gt;
    &lt;/div&gt;
`;
</code></pre>
<p>Compare that to the concatenation version from earlier and the difference is obvious. The structure is visible. You can read it like HTML.</p>
<hr />
<h2>Where Template Literals Actually Show Up</h2>
<p><strong>Building URLs and query strings</strong></p>
<pre><code class="language-javascript">const baseUrl = "https://api.example.com";
const userId = 42;
const endpoint = `\({baseUrl}/users/\){userId}/orders`;
</code></pre>
<p>Before: <code>baseUrl + "/users/" + userId + "/orders"</code>. The template version is just clearer.</p>
<p><strong>Constructing SQL or query strings</strong></p>
<pre><code class="language-javascript">const table = "products";
const limit = 10;

const query = `SELECT * FROM \({table} WHERE active = true LIMIT \){limit}`;
</code></pre>
<p><strong>Generating error messages</strong></p>
<pre><code class="language-javascript">function divide(a, b) {
    if (b === 0) {
        throw new Error(`Cannot divide ${a} by zero`);
    }
    return a / b;
}
</code></pre>
<p><strong>Logging with context</strong></p>
<pre><code class="language-javascript">console.log(`[\({new Date().toISOString()}] User \){userId} logged in from ${ip}`);
</code></pre>
<p><strong>React and JSX (or template-based rendering)</strong></p>
<p>Template literals come up a lot in dynamic class names and inline styles:</p>
<pre><code class="language-javascript">const className = `btn \({isActive ? "btn-primary" : "btn-secondary"} \){isDisabled ? "disabled" : ""}`;
</code></pre>
<hr />
<h2>Tagged Templates</h2>
<p>Tagged templates are an advanced form of template literals. You place a function name directly before the backtick, and that function gets to control what the template produces:</p>
<pre><code class="language-javascript">function tag(strings, ...values) {
    console.log(strings);   // ["Hello, ", "!"]
    console.log(values);    // ["Sameer"]
}

tag`Hello, ${"Sameer"}!`;
</code></pre>
<p>The tag function receives the static string parts as an array and the interpolated values as separate arguments. Whatever the function returns becomes the final value.</p>
<p>A simple practical use is highlighting dynamic values for debugging:</p>
<pre><code class="language-javascript">function highlight(strings, ...values) {
    return strings.reduce((result, str, i) =&gt; {
        const val = values[i] !== undefined ? `[${values[i]}]` : "";
        return result + str + val;
    }, "");
}

const user = "Arjun";
const score = 94;

console.log(highlight`Student \({user} scored \){score} marks.`);
// Student [Arjun] scored [94] marks.
</code></pre>
<hr />
<h2>A Side-by-Side Comparison</h2>
<p>Before:</p>
<pre><code class="language-javascript">function greet(user) {
    return "Hello, " + user.name + "! You have " + user.messages + " unread message" + (user.messages === 1 ? "" : "s") + ".";
}
</code></pre>
<p>After:</p>
<pre><code class="language-javascript">function greet(user) {
    const plural = user.messages === 1 ? "" : "s";
    return `Hello, \({user.name}! You have \){user.messages} unread message${plural}.`;
}
</code></pre>
<p>The second version takes less mental energy to parse. You can see the sentence structure without untangling the concatenation logic.</p>
<hr />
<h2>Conclusion</h2>
<p>Template literals are one of those features that feels minor until you use it for a week and then cannot imagine going back. The code you write is closer to the output you intend, and that gap matters when you are reading code three months after you wrote it.</p>
]]></content:encoded></item><item><title><![CDATA[Cache Strategies in Distributed Systems]]></title><description><![CDATA[Introduction
In large-scale distributed systems, performance is not an option, but a necessity. Imagine if platforms like YouTube or Twitter slowed down or went completely offline for a few hours. In ]]></description><link>https://blog.sameerbhagtani.dev/cache-strategies-in-distributed-systems</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/cache-strategies-in-distributed-systems</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[System Design]]></category><category><![CDATA[distributed systems]]></category><category><![CDATA[caching]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Wed, 18 Mar 2026 15:32:13 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/a63177e7-6d9b-4381-9a7e-601220cbdd8b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>In large-scale distributed systems, performance is not an option, but a necessity. Imagine if platforms like YouTube or Twitter slowed down or went completely offline for a few hours. In today’s world, we rely heavily on such systems, and they are expected to respond with low latency at all times.</p>
<p>A common approach to reducing latency is caching. A cache is simply a high-speed, temporary, and often in-memory data storage layer that stores a subset of frequently accessed data. It allows us to serve future requests faster, without having to hit the primary storage, such as the database.</p>
<p>This not only reduces latency but also decreases the load on the database, enabling the system to handle massive traffic efficiently.</p>
<p>Typically, every cached item has a TTL (Time-To-Live) associated with it. Once the TTL expires (for example, after 60 seconds), the cache is invalidated, and fresh data is fetched from the database as needed. This approach works well for small systems, but this naive model begins to break down at scale.</p>
<p>In distributed systems, cache expiration can lead to sudden traffic spikes, resulting in issues like the thundering herd problem. (You can read more about this in my blog post on the <a href="https://blog.sameerbhagtani.dev/thundering-herd-problem">thundering herd problem</a>.)</p>
<hr />
<h2>Basic TTL Caching is Not Enough</h2>
<p>A basic TTL-based caching approach looks like this:</p>
<blockquote>
<p>Data is cached -&gt; requests are served from the cache -&gt; TTL expires -&gt; a new request comes in, triggering a fetch from the database -&gt; and the cycle continues.</p>
</blockquote>
<p>This works well when traffic is evenly distributed and requests arrive at random intervals. In smaller systems, this approach is often sufficient.</p>
<p>However, in large-scale systems, traffic is rarely uniform. It is often bursty, with many users requesting the same data at the same time. When the cache for such frequently accessed data expires, a large number of requests suddenly start missing the cache and go directly to the database, all at once.</p>
<p>This leads to sudden load spikes, increased latency, and potential system failures.</p>
<hr />
<h2>Cache Expiry can Cause Traffic Spikes</h2>
<p>Consider the example of a social media platform, which caches popular posts to increase the overall speed. Assume the cache TTL is 60 seconds.</p>
<p>If everything is going fine, requests will hit our server, the server will fetch the post content from the cache, and return it in the response. There is no database call, and thus shorter request-response cycles.</p>
<p>However, after the 60 seconds have gone by and the cache expires, if a large number of requests come in simultaneously, since the cache is empty, each and every request will go straight to the database at the same time, resulting in the thundering herd problem. This can overload the database, increase latency, and even lead to request failures.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/5ee940b7-f7c5-4b2f-aef7-d433d5e311c2.png" alt="" style="display:block;margin:0 auto" />

<p>Clearly, we need smarter strategies to handle cache expiration in distributed systems.</p>
<hr />
<h2>Cache Management Strategies for Distributed Systems</h2>
<h3>TTL Jitter</h3>
<p>Up until now, we’ve understood that the core issue is many cached items expiring at the same time. This causes a large number of requests to hit the database simultaneously, leading to chaos. The problem isn’t traffic itself, large-scale systems are expected to handle high traffic. The real issue is <strong>synchronized traffic</strong>.</p>
<p>TTL Jitter is a simple yet effective strategy that introduces randomness into cache expiration times. Instead of assigning a fixed TTL (for example, 60 seconds), we add a small variation and set the TTL within a range, such as 50–70 seconds.</p>
<pre><code class="language-plaintext">ttl = baseTTL + random(-delta, +delta)
</code></pre>
<p>As a result, cache entries expire at different times, and incoming requests get naturally distributed instead of creating sudden spikes.</p>
<ul>
<li><p><strong>Without jitter:</strong> 10k keys expire at exactly 60s -&gt; spike</p>
</li>
<li><p><strong>With jitter:</strong> keys expire at 58s, 61s, 64s -&gt; smoother load distribution</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/cdd97c94-17b4-482c-8932-1d87ca943dc9.png" alt="" style="display:block;margin:0 auto" />

<h3>Probability-Based Early Expiration</h3>
<p>The limitation of TTL jitter is that cache entries still expire eventually. Requests will still hit the database, we’ve only found a way to distribute them more evenly.</p>
<p>To handle this more effectively, we can take a proactive approach using probabilistic early expiration.</p>
<p>Instead of waiting for the TTL to reach zero, we allow some requests to refresh the cache before it actually expires. However, we don’t want every request to do this, as that would create unnecessary load. So, we introduce probability into the decision.</p>
<p>Each incoming request has a certain chance of recomputing the cached value early. This probability is not fixed, it increases as the cache gets closer to expiration.</p>
<ul>
<li><p>When the TTL has just been set -&gt; very low probability of recomputation</p>
</li>
<li><p>As the TTL decreases -&gt; probability gradually increases</p>
</li>
<li><p>Near expiration -&gt; high probability of recomputation</p>
</li>
</ul>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/3b617c14-2ab3-441a-bb74-420f615def05.png" alt="" style="display:block;margin:0 auto" />

<p>Thus, instead of reacting at the deadline like basic TTL-based caching, this method prepares the system gradually.</p>
<h3>Mutex / Cache Locking</h3>
<p>Even with strategies like TTL jitter and probabilistic early expiration, there are still situations where multiple requests may try to recompute the same cache entry at the same time. This leads to duplicate work, where several requests hit the database simultaneously for the same data, increasing load and reducing efficiency.</p>
<p>To solve this, we can use <strong>mutex (mutual exclusion)</strong> or <strong>cache locking</strong>. When a cache entry expires and multiple requests try to fetch fresh data, only one request is allowed to recompute the value, while the others wait.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/282d1b91-fb0e-4e42-8614-67a5cbbe30ff.png" alt="" style="display:block;margin:0 auto" />

<p>The simple flow is:</p>
<ul>
<li><p>A request checks the cache</p>
</li>
<li><p>If the cache is missing or expired -&gt; it tries to acquire a lock</p>
</li>
<li><p>If it gets the lock -&gt; it fetches data from the database and updates the cache</p>
</li>
<li><p>If it doesn’t get the lock -&gt; it waits until the cache is updated</p>
</li>
</ul>
<p>The tradeoff is that this introduces additional latency for waiting requests.</p>
<h3>Stale-While-Revalidate (SWR)</h3>
<p>Even with techniques like mutex locking, some requests may still have to wait while the cache is being recomputed. This introduces additional latency, which can negatively impact user experience.</p>
<p>The idea behind SWR is: instead of blocking requests when the cache expires, we serve the stale (expired) data and refresh the cache in the background.</p>
<p>In this approach, a cached item can exist in two states:</p>
<ol>
<li><p>Fresh -&gt; within TTL, safe to serve</p>
</li>
<li><p>Stale -&gt; TTL expired, but still usable for a short duration</p>
</li>
</ol>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/88ca7481-0236-44b5-9f5e-57518b558601.png" alt="" style="display:block;margin:0 auto" />

<p>Because of this, users never have to wait for recomputation. The system continues to serve responses with low latency, while the cache gets updated asynchronously.</p>
<p>However, the tradeoff is that users may receive stale data for a short period of time. Because of this, SWR is not suitable for systems that require strict consistency, such as financial transactions or real-time critical data.</p>
<h3>Cache Warming</h3>
<p>So far, all the strategies we’ve discussed deal with cache behavior during runtime. But what if we could prepare the cache before requests even start coming in?</p>
<p>This is where cache warming (or pre-warming) comes in.</p>
<p>The idea is simple: instead of waiting for users to request data and then populating the cache (lazy loading), we proactively load frequently accessed data into the cache in advance.</p>
<p>This ensures that when the first request arrives, the data is already available in the cache, avoiding initial cache misses.</p>
<p>This can be done using:</p>
<ul>
<li><p>background jobs</p>
</li>
<li><p>scheduled tasks (cron jobs)</p>
</li>
<li><p>analytics-based predictions</p>
</li>
</ul>
<hr />
<h2>Conclusion</h2>
<p>Caching is not just about storing data to make systems faster, it’s about making the system stable under load.</p>
<p>Each of these techniques makes a tradeoff between freshness, latency, and consistency. There is no one-size-fits-all solution, the right approach depends on the nature of your system and the type of data you are dealing with.</p>
]]></content:encoded></item><item><title><![CDATA[The Thundering Herd Problem in System Design]]></title><description><![CDATA[Introduction
Imagine you're standing outside an Apple Store, waiting for the new iPhone to launch. Obviously, you're not alone. You're just one among a big crowd waiting for that door to open. As soon]]></description><link>https://blog.sameerbhagtani.dev/thundering-herd-problem</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/thundering-herd-problem</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[System Design]]></category><category><![CDATA[thundering-herd]]></category><category><![CDATA[distributed systems]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Tue, 17 Mar 2026 21:50:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/1c35c92d-d47b-4f3e-b810-3a980a237a12.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Imagine you're standing outside an Apple Store, waiting for the new iPhone to launch. Obviously, you're not alone. You're just one among a big crowd waiting for that door to open. As soon as it does, each and every single person in the crowd rushes in, out of the fear of getting left behind. And before you know it, you're caught up in chaos, everyone pushing each other around, overloading the store.</p>
<p>This is exactly what is called the "Thundering Herd Problem" in the context of system design. Many clients make a request at the same time and overwhelm a resource (server, database, etc.).</p>
<hr />
<h2>What is the Thundering Herd Problem?</h2>
<p>We all try to make our systems robust and fast, for which we adopt different system design patterns like scaling, caching, etc. However, certain loopholes in our system can lead to the "Thundering Herd Problem." Even large, robust systems suffer from this problem.</p>
<p>The Thundering Herd Problem simply refers to a large number of clients requesting a resource simultaneously, often reacting to the same event at the same time. It is not just high volume; it is simultaneous high volume.</p>
<p>Despite how the name sounds, it is important to understand that the Thundering Herd Problem is not a bug. It's just a pattern that occurs in systems with a large client base, and we need to understand why it occurs and how we can fix it.</p>
<hr />
<h2>Where Does it Commonly Occur?</h2>
<p>This problem can occur in multiple parts of a system, such as caching systems, load balancers, etc., due to different reasons:</p>
<ul>
<li><p><strong>Cache Stampede:</strong> When a highly accessed cached item expires, multiple concurrent requests bombard the database to refill the cache.</p>
</li>
<li><p><strong>Synchronized Retries:</strong> If a service fails to respond for a short period of time and then comes back online, many clients simultaneously retry failed requests, creating a spike in traffic.</p>
</li>
<li><p><strong>Cron Jobs:</strong> Multiple servers or microservices are configured to run a cron job at the exact same scheduled time.</p>
</li>
<li><p><strong>Sudden Traffic Spikes:</strong> A sudden influx of users all attempting to perform the same action at the same time, such as clicking a "Buy Now" button during a flash sale.</p>
</li>
</ul>
<hr />
<h2>Real World Example</h2>
<p>Consider the example of a social media platform, which caches popular posts to increase the overall speed. Assume the cache TTL is 60 seconds.</p>
<p>If everything is going fine, requests will hit our server, the server will fetch the post content from the cache, and return it in the response. There is no database call, and thus shorter request-response cycles.</p>
<p>However, after the 60 seconds have gone by and the cache expires, if a large number of requests come in simultaneously, since the cache is empty, each and every request will go straight to the database at the same time, resulting in the thundering herd problem.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/f912896d-40e6-4dc3-a79f-3483f51238a6.png" alt="" style="display:block;margin:0 auto" />

<p>This can overload the database, increase latency, and even lead to request failures.</p>
<hr />
<h2>Difference Between Normal Spike vs Thundering Herd</h2>
<p>In normal situations, traffic spikes happen gradually. Imagine Hotstar starts streaming IPL live. Viewers keep joining over time, and our auto-scaling configuration is able to scale the servers to handle the increasing load.</p>
<p>On the other hand, in a thundering herd situation, all the traffic comes in at once. It is not gradual, it is instantaneous and unpredictable. This results in more load on the servers and databases than the system can handle.</p>
<p>In such situations, we often enter into a chain reaction:</p>
<blockquote>
<p>More requests -&gt; DB connections get exhausted -&gt; requests start waiting -&gt; latency increases → timeouts happen → clients retry → even more load. 💥</p>
</blockquote>
<hr />
<h2>Why it Becomes Dangerous in Distributed Systems</h2>
<p>Now that you have understood the thundering herd problem, it is important to understand its impact in the context of distributed systems.</p>
<p>Distributed systems amplify this problem even further:</p>
<ul>
<li><p>There are many services and instances involved. If every request triggers 5 services, then with a spike of 100k requests, we are effectively dealing with 500k internal requests.</p>
</li>
<li><p>If one service slows down, other services depending on it also slow down, leading to cascading failures across the system.</p>
</li>
<li><p>Each service might implement its own retry logic, resulting in multiple retries across multiple services, which further multiplies the load.</p>
</li>
<li><p>Many services rely on shared resources like databases, caches, or message queues. When all services hit these resources simultaneously, they become bottlenecks and can fail under pressure.</p>
</li>
</ul>
<p>Failures in distributed systems propagate and amplify, making the thundering herd problem significantly more dangerous.</p>
<hr />
<h2>System-Level Impact</h2>
<ul>
<li><p><strong>CPU:</strong> A sudden surge in requests increases the number of active threads and processes, causing CPU usage to spike. This can lead to excessive context switching and reduced overall efficiency.</p>
</li>
<li><p><strong>Database:</strong> A large number of concurrent queries can exhaust the connection pool, slow down query execution, and potentially crash the database under heavy load.</p>
</li>
<li><p><strong>Cache:</strong> During a cache miss storm, the cache becomes temporarily ineffective, forcing repeated requests to hit the database and increasing pressure on backend systems.</p>
</li>
<li><p><strong>Latency:</strong> As requests start queuing up, response times increase significantly. This leads to timeouts, failed requests, and a poor user experience.</p>
</li>
</ul>
<p>The impact is not isolated, it affects every layer of the system.</p>
<hr />
<h2>Techniques to Minimize It</h2>
<h3>Request Coalescing</h3>
<p>Instead of allowing all requests to go to the database to refill the cache, we ensure that only one request performs this operation. When multiple requests arrive for the same data, one request fetches the data from the database and updates the cache, while the others wait and reuse the same result.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/78aa4583-f2fb-4dd5-bffb-39c9d09f86f1.png" alt="" style="display:block;margin:0 auto" />

<p>This prevents duplicate work and reduces unnecessary load on the database.</p>
<h3>Cache Locking / Mutex</h3>
<p>Cache locking (or mutex) is a technique used to ensure that only one request can regenerate the cache at a time. When a request detects a cache miss, it acquires a lock and proceeds to fetch data from the database. Other requests are blocked or wait until the lock is released.</p>
<h3>Staggered Expiry</h3>
<p>Staggered Expiry is another technique that focuses on making sure that all the cached data does not expire at once. To achieve this, we introduce a small random variation (jitter) in their expiry times.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/d8657fe7-e4f0-456a-aaf1-cfa3497fc225.png" alt="" style="display:block;margin:0 auto" />

<p>This reduces the chances of a sudden spike in load, by spreading out requests over time.</p>
<h3>Exponential Backoff</h3>
<p>When a request fails, you don’t just try again right away. With exponential backoff, you wait a bit, and each time you fail again, you wait even longer. The delay grows fast, so clients don’t all hammer the server at once.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/2e02f9df-c263-4370-b148-487c0a33fc56.png" alt="" style="display:block;margin:0 auto" />

<p>It spreads out the load and keeps the system from getting overloaded.</p>
<h3>Rate Limiting</h3>
<p>Rate limiting sets a cap on how many times a client can hit the system in a given period. If you go over that number, your requests get blocked or slowed down. This keeps the service from getting swamped and makes sure everyone gets a fair shot at the resources.</p>
<hr />
<h2>Conclusion</h2>
<p>The thundering herd problem is not caused by high traffic alone, but by many requests happening at the same time due to a shared trigger. While it can lead to serious issues in distributed systems, it can be effectively managed using the right techniques such as request coalescing, staggered expiry, backoff strategies, and rate limiting.</p>
<p>By understanding the root cause and applying these strategies, we can build systems that remain stable even under sudden spikes in load.</p>
]]></content:encoded></item><item><title><![CDATA[The Magic of this, call(), apply(), and bind() in JavaScript]]></title><description><![CDATA[Introduction
If you've spent any time with JavaScript, you've probably run into this and walked away confused. It behaves differently depending on where it shows up. And call(), apply(), and bind() so]]></description><link>https://blog.sameerbhagtani.dev/this-call-apply-and-bind-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/this-call-apply-and-bind-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[ Arrow Functions In JavaScript]]></category><category><![CDATA[this keyword]]></category><category><![CDATA[call apply and bind methods]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Sat, 14 Mar 2026 11:15:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/5acc9a75-16f9-48b8-85b7-fb8db431d05e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've spent any time with JavaScript, you've probably run into <code>this</code> and walked away confused. It behaves differently depending on where it shows up. And <code>call()</code>, <code>apply()</code>, and <code>bind()</code> sound similar enough that most people lump them together without really understanding what each one does differently.</p>
<p>This post clears all of that up. No execution context internals, no spec language. Just what you need to know to write better code.</p>
<hr />
<h2>What <code>this</code> Actually Means</h2>
<p>The simplest way to think about <code>this</code>: it refers to whoever called the function.</p>
<p>Not where the function was defined. Not where it lives in your code. Who called it.</p>
<p>That one shift in thinking makes most of the confusion go away.</p>
<hr />
<h2><code>this</code> Inside a Regular Function</h2>
<pre><code class="language-javascript">function greet() {
    console.log(this);
}

greet();
</code></pre>
<p>When you call a plain function like this, <code>this</code> points to the global object. In a browser, that's <code>window</code>. In Node.js, it's <code>global</code>. In strict mode, it's <code>undefined</code>.</p>
<p>Nobody specific called it, so JavaScript falls back to the global object by default.</p>
<hr />
<h2><code>this</code> Inside an Object</h2>
<p>Things get more useful when functions live inside objects.</p>
<pre><code class="language-javascript">const person = {
    name: "Alice",
    greet: function () {
        console.log("Hi, I'm " + this.name);
    }
};

person.greet(); // Hi, I'm Alice
</code></pre>
<p>Here, <code>person</code> is the one calling <code>greet</code>. So <code>this</code> is <code>person</code>, and <code>this.name</code> is <code>"Alice"</code>.</p>
<p>Now watch what happens when you pull the function out of the object:</p>
<pre><code class="language-javascript">const greet = person.greet;
greet(); // Hi, I'm undefined
</code></pre>
<p>The function is the same. But now nobody owns the call. <code>this</code> falls back to the global object, and <code>name</code> isn't defined there, so you get <code>undefined</code>.</p>
<p>This is the source of most <code>this</code> bugs.</p>
<hr />
<h2><code>call()</code>: Borrow a Function, Choose Your <code>this</code></h2>
<p><code>call()</code> lets you run a function and tell it exactly what <code>this</code> should be.</p>
<pre><code class="language-javascript">const person1 = { name: "Alice" };
const person2 = { name: "Bob" };

function greet(city) {
    console.log(this.name + " lives in " + city);
}

greet.call(person1, "New York"); // Alice lives in New York
greet.call(person2, "London");   // Bob lives in London
</code></pre>
<p>The first argument to <code>call()</code> sets <code>this</code>. Everything after that gets passed as individual arguments to the function.</p>
<p>Think of it as: "Run this function, but pretend it belongs to this object."</p>
<hr />
<h2><code>apply()</code>: Same Idea, Arguments as an Array</h2>
<p><code>apply()</code> works exactly like <code>call()</code>. The only difference is how you pass arguments. Instead of listing them one by one, you pass an array.</p>
<pre><code class="language-javascript">function greet(city, country) {
    console.log(this.name + " is from " + city + ", " + country);
}

const person = { name: "Alice" };

greet.apply(person, ["Paris", "France"]); // Alice is from Paris, France
</code></pre>
<p>Both lines below do the same thing:</p>
<pre><code class="language-javascript">greet.call(person, "Paris", "France");
greet.apply(person, ["Paris", "France"]);
</code></pre>
<p><code>apply()</code> is handy when your arguments are already stored in an array.</p>
<hr />
<h2><code>bind()</code>: Create a Fixed Version of a Function</h2>
<p><code>call()</code> and <code>apply()</code> run the function immediately. <code>bind()</code> is different. It returns a new function with <code>this</code> permanently locked in, but doesn't call it yet.</p>
<pre><code class="language-javascript">const person = { name: "Alice" };

function greet() {
    console.log("Hi, I'm " + this.name);
}

const greetAlice = greet.bind(person);

greetAlice(); // Hi, I'm Alice
greetAlice(); // Hi, I'm Alice (always Alice, no matter what)
</code></pre>
<p>You can store that bound function and call it later. It will always use the <code>this</code> you gave it.</p>
<p>This is especially useful for event handlers and callbacks, where you lose control of what <code>this</code> will be.</p>
<pre><code class="language-javascript">const button = {
    label: "Submit",
    handleClick: function () {
        console.log("Clicked: " + this.label);
    }
};

const handler = button.handleClick.bind(button);

// Later, passed as a callback
setTimeout(handler, 1000); // Clicked: Submit
</code></pre>
<p>Without <code>bind()</code>, <code>this</code> inside <code>setTimeout</code> would not be <code>button</code>.</p>
<hr />
<h2>Comparison: <code>call</code> vs <code>apply</code> vs <code>bind</code></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>Runs the function?</td>
<td>Yes, immediately</td>
<td>Yes, immediately</td>
<td>No, returns a new function</td>
</tr>
<tr>
<td>How you pass args</td>
<td>One by one</td>
<td>As an array</td>
<td>One by one (at bind time or call time)</td>
</tr>
<tr>
<td>Fixes <code>this</code>?</td>
<td>For that call only</td>
<td>For that call only</td>
<td>Permanently</td>
</tr>
<tr>
<td>Returns</td>
<td>Function result</td>
<td>Function result</td>
<td>New function</td>
</tr>
</tbody></table>
<hr />
<h2>When to Use Each One</h2>
<p>Use <code>call()</code> when you want to run a function once with a specific <code>this</code> and you have the arguments ready individually.</p>
<p>Use <code>apply()</code> when you have the same situation but your arguments are already in an array.</p>
<p>Use <code>bind()</code> when you need to pass a function somewhere (a callback, an event listener, a timeout) and you want to make sure <code>this</code> stays what you intend it to be.</p>
<hr />
<h2>One More Thing Worth Knowing</h2>
<p>Arrow functions ignore all of this. They don't have their own <code>this</code>. They inherit it from the surrounding scope and <code>call()</code>, <code>apply()</code>, and <code>bind()</code> cannot change that.</p>
<pre><code class="language-javascript">const person = {
    name: "Alice",
    greet: () =&gt; {
        console.log(this.name); // undefined, always
    }
};

person.greet();
</code></pre>
<p>Arrow functions are great in many situations, but if you need <code>this</code> to refer to the object, use a regular function.</p>
<hr />
<h2>Conclusion</h2>
<p>Once you stop thinking of <code>this</code> as something mysterious and start thinking of it as "who called this function," the rest follows. <code>call()</code> and <code>apply()</code> let you pick the caller. <code>bind()</code> locks one in for good.</p>
]]></content:encoded></item><item><title><![CDATA[Object-Oriented Programming in JavaScript]]></title><description><![CDATA[Introduction
If you've been writing JavaScript for a while, you've probably reached a point where your code starts feeling messy. Variables everywhere, functions loosely scattered around, and duplicat]]></description><link>https://blog.sameerbhagtani.dev/oop-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/oop-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[oop]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[classes]]></category><category><![CDATA[Objects]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Fri, 13 Mar 2026 12:51:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/d2678281-e0ec-4327-97fc-aef7504a2266.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've been writing JavaScript for a while, you've probably reached a point where your code starts feeling messy. Variables everywhere, functions loosely scattered around, and duplicated logic in three different places. OOP is one way to bring order to that chaos.</p>
<hr />
<h2>The Blueprint Analogy</h2>
<p>Think about how a car manufacturer works. They don't build each car from scratch, deciding on the fly where the steering wheel goes. They create a blueprint first. That blueprint defines what every car will have: an engine, four wheels, a color, a speed limit. Then they stamp out as many cars as they need from that blueprint.</p>
<p>In JavaScript, a <strong>class</strong> is the blueprint. An <strong>object</strong> is the car.</p>
<p>Every object you create from a class gets its own copy of the properties, but they all follow the same structure.</p>
<hr />
<h2>What a Class Looks Like</h2>
<p>Here's a basic <code>Car</code> class:</p>
<pre><code class="language-javascript">class Car {
    constructor(brand, color) {
        this.brand = brand;
        this.color = color;
    }

    describe() {
        console.log("This is a " + this.color + " " + this.brand + ".");
    }
}
</code></pre>
<p>Nothing runs yet. This is just the blueprint.</p>
<hr />
<h2>Creating Objects from a Class</h2>
<p>To actually make a car, you use the <code>new</code> keyword:</p>
<pre><code class="language-javascript">const myCar = new Car("Toyota", "red");
const yourCar = new Car("Honda", "blue");

myCar.describe();   // This is a red Toyota.
yourCar.describe(); // This is a blue Honda.
</code></pre>
<p>Both <code>myCar</code> and <code>yourCar</code> are objects created from the same <code>Car</code> class. Same structure, different data. That's the point of reusability.</p>
<hr />
<h2>The Constructor Method</h2>
<p>The <code>constructor</code> is a special method that runs automatically when you create a new object. You use it to set up the initial values.</p>
<pre><code class="language-javascript">class Person {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}

const alice = new Person("Alice", 30);
console.log(alice.name); // Alice
console.log(alice.age);  // 30
</code></pre>
<p><code>this</code> refers to the specific object being created. When <code>alice</code> is created, <code>this.name</code> becomes <code>alice.name</code>. When you create a second person, <code>this</code> refers to that one instead.</p>
<hr />
<h2>Adding Methods</h2>
<p>Methods are functions that belong to a class. They define what an object can <em>do</em>.</p>
<pre><code class="language-javascript">class Student {
    constructor(name, grade) {
        this.name = name;
        this.grade = grade;
    }

    introduce() {
        console.log("Hi, I'm " + this.name + " and I'm in grade " + this.grade + ".");
    }

    isPassing() {
        return this.grade &gt;= 50;
    }
}

const raj = new Student("Raj", 72);
raj.introduce();          // Hi, I'm Raj and I'm in grade 72.
console.log(raj.isPassing()); // true
</code></pre>
<p>You're not repeating the logic for <code>isPassing</code> every time you check a student. Write it once in the class, use it on any object.</p>
<hr />
<h2>Reusability in Practice</h2>
<p>Say you need 50 student objects. Without classes, you'd either write 50 objects by hand or build some awkward factory function. With a class, you just do:</p>
<pre><code class="language-javascript">const students = [
    new Student("Priya", 88),
    new Student("Arjun", 45),
    new Student("Meera", 91),
];

students.forEach(s =&gt; {
    console.log(s.name + ": " + (s.isPassing() ? "Pass" : "Fail"));
});
</code></pre>
<p>Same structure, consistent behavior, zero repetition.</p>
<hr />
<h2>Encapsulation: Keep Related Things Together</h2>
<p>Encapsulation means bundling data (properties) and behavior (methods) into one place. Instead of having a <code>studentName</code> variable floating somewhere and a <code>checkGrade</code> function somewhere else, you keep everything inside the class where it belongs.</p>
<pre><code class="language-javascript">class BankAccount {
    constructor(owner, balance) {
        this.owner = owner;
        this.balance = balance;
    }

    deposit(amount) {
        this.balance += amount;
        console.log("Deposited " + amount + ". New balance: " + this.balance);
    }

    withdraw(amount) {
        if (amount &gt; this.balance) {
            console.log("Insufficient funds.");
        } else {
            this.balance -= amount;
            console.log("Withdrew " + amount + ". New balance: " + this.balance);
        }
    }
}

const account = new BankAccount("Nisha", 1000);
account.deposit(500);   // Deposited 500. New balance: 1500
account.withdraw(200);  // Withdrew 200. New balance: 1300
</code></pre>
<p>The logic for deposits and withdrawals lives inside the class. Anyone using a <code>BankAccount</code> object doesn't need to think about how the math works. They just call <code>deposit</code> or <code>withdraw</code>.</p>
<p>That's encapsulation. The object manages its own state, and exposes clean methods to interact with it.</p>
<hr />
<h2>Summary</h2>
<p>Here's a quick summary of the pieces:</p>
<ul>
<li><p>A <strong>class</strong> is a template or blueprint</p>
</li>
<li><p>The <strong>constructor</strong> runs when you create a new object and sets initial values</p>
</li>
<li><p><strong>Methods</strong> are functions defined inside the class</p>
</li>
<li><p><strong>Objects</strong> are instances created from the class using <code>new</code></p>
</li>
<li><p><strong>Encapsulation</strong> means keeping related data and behavior in one place</p>
</li>
</ul>
<p>OOP doesn't solve every problem, and JavaScript has other patterns too. But once your programs get complex enough that you're managing multiple entities with shared behavior, classes are worth knowing well.</p>
]]></content:encoded></item><item><title><![CDATA[Array Methods You Must Know]]></title><description><![CDATA[Introduction
Arrays are at the center of almost every JavaScript program. You filter data, transform lists, compute totals, add or remove items. Knowing the right method means writing 3 lines instead ]]></description><link>https://blog.sameerbhagtani.dev/array-methods-you-must-know</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/array-methods-you-must-know</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[arrays]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Tue, 10 Mar 2026 06:09:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/d169026b-ab49-42f4-94cf-cc891534037f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Arrays are at the center of almost every JavaScript program. You filter data, transform lists, compute totals, add or remove items. Knowing the right method means writing 3 lines instead of 15. Here are the ones you'll use constantly.</p>
<hr />
<h2><code>push()</code> and <code>pop()</code></h2>
<p>These two are the simplest. <code>push()</code> adds an item to the end of an array. <code>pop()</code> removes the last item.</p>
<pre><code class="language-javascript">const fruits = ['apple', 'banana'];

fruits.push('mango');
// ['apple', 'banana', 'mango']

fruits.pop();
// ['apple', 'banana']
</code></pre>
<p><code>push()</code> returns the new length of the array. <code>pop()</code> returns the item it removed. That returned value is easy to forget about but occasionally useful.</p>
<hr />
<h2><code>shift()</code> and <code>unshift()</code></h2>
<p>Same idea as push/pop, but at the front of the array instead of the end.</p>
<p><code>unshift()</code> adds to the front. <code>shift()</code> removes from the front.</p>
<pre><code class="language-javascript">const queue = ['task1', 'task2'];

queue.unshift('task0');
// ['task0', 'task1', 'task2']

queue.shift();
// ['task1', 'task2']
</code></pre>
<p>A good way to remember: "shift" moves everything over (like shifting gears), while "unshift" pushes things back in at the start.</p>
<p>Worth noting: <code>shift()</code> and <code>unshift()</code> are slower than <code>pop()</code> and <code>push()</code> on large arrays because every element has to be re-indexed. For most code you'll write, it won't matter.</p>
<hr />
<h2><code>map()</code></h2>
<p><code>map()</code> goes through every item in an array and returns a new array with each item transformed.</p>
<p>Say you have a list of prices and you want to apply a 10% discount to all of them. The traditional way:</p>
<pre><code class="language-javascript">const prices = [100, 200, 300];
const discounted = [];

for (let i = 0; i &lt; prices.length; i++) {
    discounted.push(prices[i] * 0.9);
}
// [90, 180, 270]
</code></pre>
<p>With <code>map()</code>:</p>
<pre><code class="language-javascript">const prices = [100, 200, 300];

const discounted = prices.map(function(price) {
    return price * 0.9;
});
// [90, 180, 270]
</code></pre>
<p>The original <code>prices</code> array stays untouched. <code>map()</code> always returns a brand-new array. That's important: use it when you want to transform data without modifying the source.</p>
<hr />
<h2><code>filter()</code></h2>
<p><code>filter()</code> goes through each item and keeps only the ones that pass a condition. It returns a new array with the matching items.</p>
<p>Here's the for-loop version:</p>
<pre><code class="language-javascript">const scores = [45, 82, 91, 36, 67];
const passing = [];

for (let i = 0; i &lt; scores.length; i++) {
    if (scores[i] &gt;= 60) {
    passing.push(scores[i]);
    }
}
// [82, 91, 67]
</code></pre>
<p>With <code>filter()</code>:</p>
<pre><code class="language-javascript">const scores = [45, 82, 91, 36, 67];

const passing = scores.filter(function(score) {
    return score &gt;= 60;
});
// [82, 91, 67]
</code></pre>
<p>The callback returns <code>true</code> or <code>false</code>. If it returns <code>true</code>, the item gets included. If <code>false</code>, it gets dropped.</p>
<hr />
<h2><code>reduce()</code></h2>
<p><code>reduce()</code> is the one that trips people up at first. The name is a bit abstract, but the idea is practical: you're collapsing an array down to a single value.</p>
<p>The simplest use case is a sum:</p>
<pre><code class="language-javascript">const numbers = [10, 20, 30, 40];

const total = numbers.reduce(function(accumulator, current) {
    return accumulator + current;
}, 0);
// 100
</code></pre>
<p>Here's what's happening step by step:</p>
<ul>
<li><p>Start with <code>accumulator = 0</code> (that's the <code>0</code> at the end, called the initial value)</p>
</li>
<li><p>First round: <code>0 + 10 = 10</code></p>
</li>
<li><p>Second round: <code>10 + 20 = 30</code></p>
</li>
<li><p>Third round: <code>30 + 30 = 60</code></p>
</li>
<li><p>Fourth round: <code>60 + 40 = 100</code></p>
</li>
</ul>
<p>The <code>accumulator</code> carries the running result. The <code>current</code> is the item being processed.</p>
<p>If you're not passing an initial value, <code>reduce()</code> uses the first element as the starting accumulator and begins from the second. That can cause bugs, so the habit of always providing an initial value is worth developing early.</p>
<hr />
<h2><code>forEach()</code></h2>
<p><code>forEach()</code> runs a function on each item in the array. That's it. It doesn't return anything.</p>
<pre><code class="language-javascript">const names = ['Alice', 'Bob', 'Charlie'];

names.forEach(function(name) {
    console.log('Hello, ' + name);
});

// Hello, Alice
// Hello, Bob
// Hello, Charlie
</code></pre>
<p>Where it gets confusing: people sometimes reach for <code>forEach()</code> when they should use <code>map()</code>. The difference is intent. If you want a new array back, use <code>map()</code>. If you're doing something as a side effect (logging, sending a request, updating the DOM), use <code>forEach()</code>.</p>
<p><code>forEach()</code> always returns <code>undefined</code>. Trying to assign its result to a variable and use it as an array is a common mistake.</p>
<hr />
<h2>A Quick Comparison</h2>
<table>
<thead>
<tr>
<th>Method</th>
<th>Returns</th>
<th>Use when</th>
</tr>
</thead>
<tbody><tr>
<td><code>push()</code> / <code>pop()</code></td>
<td>length or removed item</td>
<td>adding/removing at the end</td>
</tr>
<tr>
<td><code>shift()</code> / <code>unshift()</code></td>
<td>length or removed item</td>
<td>adding/removing at the front</td>
</tr>
<tr>
<td><code>map()</code></td>
<td>new array</td>
<td>transforming every item</td>
</tr>
<tr>
<td><code>filter()</code></td>
<td>new array</td>
<td>keeping items that match a condition</td>
</tr>
<tr>
<td><code>reduce()</code></td>
<td>single value</td>
<td>computing a total, building an object</td>
</tr>
<tr>
<td><code>forEach()</code></td>
<td><code>undefined</code></td>
<td>side effects only</td>
</tr>
</tbody></table>
<hr />
<h2>What to Practice Next</h2>
<p>Try using <code>map()</code> to build a list of HTML strings from an array of data. Use <code>filter()</code> to remove empty or invalid items from a form response. Use <code>reduce()</code> to count how many times each word appears in a sentence.</p>
<p>Once these six methods feel automatic, you'll find yourself writing smaller, cleaner code, and you'll also have the foundation to start combining them when needed.</p>
]]></content:encoded></item><item><title><![CDATA[Function Declaration vs Function Expression in JavaScript]]></title><description><![CDATA[Introduction
If you've been writing JavaScript for a while, you've probably used both without thinking much about which one you're reaching for. They look similar, and for basic cases, they behave sim]]></description><link>https://blog.sameerbhagtani.dev/function-declaration-vs-function-expression</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/function-declaration-vs-function-expression</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[functions]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Mon, 09 Mar 2026 08:44:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/c8ff0788-7f13-4b0a-aa84-e08fb82e24df.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've been writing JavaScript for a while, you've probably used both without thinking much about which one you're reaching for. They look similar, and for basic cases, they behave similarly too. But they're not the same thing, and the difference actually matters once your code grows past a few lines.</p>
<hr />
<h2>What a Function Is (And Why It Exists)</h2>
<p>A function is a block of code you can name and reuse. Without functions, you'd write the same logic everywhere it's needed. With functions, you write it once and call it whenever.</p>
<p>That's it. No mystery. Here's the clearest example:</p>
<pre><code class="language-javascript">// Without a function
let result1 = 5 + 3;
let result2 = 10 + 3;
let result3 = 7 + 3;

// With a function
function addThree(num) {
    return num + 3;
}

let result1 = addThree(5);
let result2 = addThree(10);
let result3 = addThree(7);
</code></pre>
<p>If the logic changes later, you fix it in one place instead of hunting through every file.</p>
<hr />
<h2>Function Declaration</h2>
<p>A function declaration is what most people learn first. You write the <code>function</code> keyword, give it a name, and define the body.</p>
<pre><code class="language-javascript">function add(a, b) {
    return a + b;
}

console.log(add(2, 3)); // 5
</code></pre>
<p>Clean and readable. The function has a name (<code>add</code>), takes two parameters, and returns their sum.</p>
<hr />
<h2>Function Expression</h2>
<p>A function expression is when you assign a function to a variable.</p>
<pre><code class="language-javascript">const add = function(a, b) {
    return a + b;
};

console.log(add(2, 3)); // 5
</code></pre>
<p>Same behavior here. You're still calling <code>add(2, 3)</code> and getting <code>5</code>. The difference is in <em>how</em> the function was created, not what it does.</p>
<p>You can also use arrow function syntax, which is just a shorter way to write a function expression:</p>
<pre><code class="language-javascript">const add = (a, b) =&gt; a + b;

console.log(add(2, 3)); // 5
</code></pre>
<p>Arrow functions are common in modern JavaScript. They're still function expressions, just written more compactly.</p>
<hr />
<h2>The Big Difference: Hoisting</h2>
<p>This is where things actually diverge.</p>
<p>JavaScript does something called <strong>hoisting</strong> before running your code. It scans the file and moves certain declarations to the top. Function declarations get fully hoisted, meaning the browser knows about the entire function before any code runs.</p>
<p>So this works:</p>
<pre><code class="language-javascript">console.log(add(2, 3)); // 5 -- called before the function is defined

function add(a, b) {
    return a + b;
}
</code></pre>
<p>You called <code>add</code> before it was written in the file, and JavaScript didn't complain. That's hoisting in action.</p>
<p>Now try the same thing with a function expression:</p>
<pre><code class="language-javascript">console.log(add(2, 3)); // Error: Cannot access 'add' before initialization

const add = function(a, b) {
    return a + b;
};
</code></pre>
<p>This throws an error. The variable <code>add</code> is hoisted (JavaScript knows it exists), but its value isn't assigned yet when you try to call it. You have to define it before using it.</p>
<p>The short version: declarations are available anywhere in their scope, expressions are only available after the line where they're defined.</p>
<hr />
<h2>Key Differences at a Glance</h2>
<table>
<thead>
<tr>
<th>Point</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 (only the variable)</td>
</tr>
<tr>
<td>Can call before definition</td>
<td>Yes</td>
<td>No</td>
</tr>
<tr>
<td>Named</td>
<td>Always</td>
<td>Optional</td>
</tr>
</tbody></table>
<hr />
<h2>When to Use Each</h2>
<p><strong>Use a function declaration</strong> when you're writing utility functions or anything that should be available throughout a file. The hoisting behavior means you can organize your file however reads best, putting helper functions at the bottom even if the main logic uses them higher up.</p>
<pre><code class="language-javascript">// This is fine -- greet is hoisted
greet("Sam");

function greet(name) {
    console.log("Hello, " + name);
}
</code></pre>
<p><strong>Use a function expression</strong> when you need to assign a function dynamically, pass it as an argument, or return it from another function. Expressions treat functions as values, which is what makes callbacks and higher-order functions work.</p>
<pre><code class="language-javascript">const numbers = [1, 2, 3, 4];
const doubled = numbers.map(function(n) {
    return n * 2;
});

// Or with arrow syntax
const doubled = numbers.map(n =&gt; n * 2);
</code></pre>
<p>You'd never write a function declaration inline like that. Expressions fit naturally wherever a value would go.</p>
<p><strong>Arrow functions specifically</strong> are worth using when you don't need your own <code>this</code> context (they inherit <code>this</code> from the surrounding scope). For callbacks, array methods, and short transformations, they're the go-to.</p>
<hr />
<h2>A Practical Rule of Thumb</h2>
<p>If you're defining a standalone, named function that you'll reuse across your file, go with a declaration. If you're passing a function somewhere, storing it in a variable, or building it conditionally, go with an expression.</p>
<p>Neither is universally better. The right choice comes down to what your code is doing and what makes the intent clear to whoever reads it next.</p>
]]></content:encoded></item><item><title><![CDATA[Understanding Objects in JavaScript]]></title><description><![CDATA[Introduction
If you've written any JavaScript, you've probably used an array to store a list of values. Arrays are great for ordered data. But what if you need to describe something, not just list thi]]></description><link>https://blog.sameerbhagtani.dev/objects-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/objects-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Objects]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Mon, 09 Mar 2026 05:13:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/e351e576-dab7-4878-b730-e909d376d020.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've written any JavaScript, you've probably used an array to store a list of values. Arrays are great for ordered data. But what if you need to describe something, not just list things?</p>
<p>That's where objects come in.</p>
<hr />
<h2>What is an Object?</h2>
<p>An object in JavaScript is a collection of key-value pairs. Each key is a string (called a property), and each value can be anything: a number, a string, a boolean, even another object or a function.</p>
<p>Think of it like a contact card. A contact card doesn't just hold a list, it holds labeled information: a name, a phone number, a city. That labeled structure is exactly what an object gives you.</p>
<p>Here's the difference made concrete:</p>
<pre><code class="language-javascript">// An array: ordered, but no labels
const person = ["Alice", 30, "Mumbai"];

// An object: labeled, descriptive
const person = {
    name: "Alice",
    age: 30,
    city: "Mumbai"
};
</code></pre>
<p>With the array, you have to remember that index 0 is the name and index 2 is the city. With the object, the data explains itself.</p>
<hr />
<h2>Creating an Object</h2>
<p>The most common way to create an object is with curly braces, also called object literal syntax.</p>
<pre><code class="language-javascript">const person = {
    name: "Alice",
    age: 30,
    city: "Mumbai"
};
</code></pre>
<p>Each line inside is a property. The key is on the left, the value is on the right, and they're separated by a colon. Properties are separated by commas.</p>
<p>You can also create an empty object and add properties later:</p>
<pre><code class="language-javascript">const person = {};
person.name = "Alice";
person.age = 30;
</code></pre>
<p>Both approaches are valid. Object literals are more common when you know the data upfront.</p>
<hr />
<h2>Accessing Properties</h2>
<p>There are two ways to read a property from an object.</p>
<h3>Dot Notation</h3>
<pre><code class="language-javascript">console.log(person.name); // "Alice"
console.log(person.age);  // 30
</code></pre>
<p>This is the standard way. Clean, readable, and works most of the time.</p>
<h3>Bracket Notation</h3>
<pre><code class="language-javascript">console.log(person["name"]); // "Alice"
console.log(person["city"]); // "Mumbai"
</code></pre>
<p>Bracket notation is useful when the property name is stored in a variable:</p>
<pre><code class="language-javascript">const key = "age";
console.log(person[key]); // 30
</code></pre>
<p>You can't do that with dot notation. <code>person.key</code> would look for a property literally named "key", not the value stored in the variable.</p>
<hr />
<h2>Updating Properties</h2>
<p>To change a property's value, just reassign it:</p>
<pre><code class="language-javascript">person.age = 31;
console.log(person.age); // 31
</code></pre>
<p>Works the same way with bracket notation:</p>
<pre><code class="language-javascript">person["city"] = "Pune";
console.log(person.city); // "Pune"
</code></pre>
<p>There's nothing special about updating vs. setting. If the property exists, the value gets replaced. If it doesn't exist, the property gets created.</p>
<hr />
<h2>Adding and Deleting Properties</h2>
<p>You can add new properties to an object at any time, even after it's been created:</p>
<pre><code class="language-javascript">person.email = "alice@example.com";
console.log(person.email); // "alice@example.com"
</code></pre>
<p>To remove a property, use the <code>delete</code> keyword:</p>
<pre><code class="language-javascript">delete person.city;
console.log(person.city); // undefined
</code></pre>
<p>After deletion, accessing that property returns <code>undefined</code>. The key is gone.</p>
<hr />
<h2>Looping Through an Object</h2>
<p>If you want to go through all the properties in an object, <code>for...in</code> is the most direct way:</p>
<pre><code class="language-javascript">for (let key in person) {
    console.log(key, ":", person[key]);
}

// name : Alice
// age : 31
// email : alice@example.com
</code></pre>
<p>On each iteration, <code>key</code> holds the property name as a string. <code>person[key]</code> gives you the value for that property. Notice bracket notation here; dot notation won't work because <code>key</code> is a variable.</p>
<p>You can also use <code>Object.keys()</code>, <code>Object.values()</code>, and <code>Object.entries()</code> if you want to work with the keys or values as arrays:</p>
<pre><code class="language-javascript">console.log(Object.keys(person));
// ["name", "age", "email"]

console.log(Object.values(person));
// ["Alice", 31, "alice@example.com"]

Object.entries(person).forEach(([key, value]) =&gt; {
    console.log(key, ": ", value);
});
</code></pre>
<p><code>Object.entries()</code> is particularly handy when you need both the key and value together without the <code>for...in</code> syntax.</p>
<hr />
<h2>Putting It Together</h2>
<p>Here's everything applied to one object:</p>
<pre><code class="language-javascript">const person = {
    name: "Alice",
    age: 30,
    city: "Mumbai"
};

// Access
console.log(person.name);       // "Alice"
console.log(person["city"]);    // "Mumbai"

// Update
person.age = 31;

// Add
person.email = "alice@example.com";

// Delete
delete person.city;

// Loop
for (let key in person) {
    console.log(key + ": " + person[key]);
}

// name: Alice
// age: 31
// email: alice@example.com
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>Objects are one of the most-used structures in JavaScript. Once you're comfortable with creating, reading, updating, and looping through them, a lot of JavaScript code starts making more sense because objects show up everywhere: in API responses, in function arguments, in component state, and more.</p>
]]></content:encoded></item><item><title><![CDATA[Operators: Welcome to the JavaScript Cafe]]></title><description><![CDATA[Introduction
Imagine walking into a cafe called the "JavaScript Cafe". Just like any other typical cafe, this one too has several ingredients, chefs who decide what to do with these ingredients as per]]></description><link>https://blog.sameerbhagtani.dev/operators-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/operators-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Operators]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Sat, 07 Mar 2026 22:34:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/e843d01e-7b91-4a6c-8335-d2b79bf51fca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>Imagine walking into a cafe called the "JavaScript Cafe". Just like any other typical cafe, this one too has several ingredients, chefs who decide what to do with these ingredients as per the customer's wishes, and finally they create some dish based on the requirements.</p>
<p>If you think about it, we basically take some data (ingredients), put them together using some operations (as decided by the chefs), and create a final dish (result).</p>
<p>Programming works in a similar fashion. In every programming language, including JavaScript, we have a foundational concept called operators. In this blog post, we are going to explore what operators are, how they help us build expressions and all the different types of operators, all with a fun analogy of a cafe, particularly the JavaScript Cafe!</p>
<hr />
<h2>Tokens: Building Blocks of any Language</h2>
<p>Before we get into operators, let's briefly talk about tokens. Whenever we write any program, the compiler/interpreter behind that language breaks it all down into tokens. Tokens are the smallest meaningful units of code in any language. The JavaScript engine also breaks down the code into these bits and pieces called tokens.</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/d3cdfec4-1c5d-4a50-b7d8-129c37f2b1c1.png" alt="Diagram showing how the JavaScript statement let x = 5; is broken into tokens: let (keyword), x (identifier), = (operator), 5 (literal), and ; (separator)." style="display:block;margin:0 auto" />

<p>You can think of tokens like words in a sentence. Just like sentences are made of words, programs are made up of tokens.</p>
<p>JavaScript has the following types of tokens:</p>
<h3>Keywords</h3>
<p>These are reserved or pre-defined words that have a special meaning.</p>
<p>Examples include:</p>
<pre><code class="language-javascript">let
const
function
return
if
else
class
await
</code></pre>
<h3>Identifiers</h3>
<p>These are names that we programmers give to variables, functions, classes, or objects.</p>
<p>Examples include:</p>
<pre><code class="language-javascript">let username = "Sameer";

function add(a, b) {
    return a + b;
}
</code></pre>
<ul>
<li>In the above example, <code>username</code> and <code>add</code> are identifiers.</li>
</ul>
<h3>Literals</h3>
<p>These represent fixed values written directly in code.</p>
<p>Examples include:</p>
<pre><code class="language-javascript">42
"Hello"
true
null
</code></pre>
<h3>Separators</h3>
<p>These are symbols used to structure the code.</p>
<p>Examples include:</p>
<pre><code class="language-javascript">;
,
.
()
{}
[]
:
</code></pre>
<h3>Comments</h3>
<p>Comments are simply some annotations in our code, that are straight up ignored by the JavaScript engine. These are useful for documentation.</p>
<p>Examples include:</p>
<pre><code class="language-javascript">// this is a single line comment

/*
this is a
multi-line
comment
*/
</code></pre>
<h3>Operators</h3>
<p>And finally, we have our operators. This blog post is specifically about operators in JavaScript. However, this brief section was important to help you understand that operators are simply some of many tokens that have a special meaning to the language.</p>
<p>Now what exactly are operators, why do we need them, etc. will all be covered in the rest of this blog post.</p>
<hr />
<h2>What are Operators?</h2>
<p>Before getting into the types of operators, we need to understand what they even are, and why do we need them. The definition goes like:</p>
<blockquote>
<p>Operators are symbols or keywords in programming that perform operations on variables and values (operands) to manipulate data.</p>
</blockquote>
<p>However, such long and boring technical definitions do not enable us to understand and remember the concept easily. So let's take the example of our JavaScript Cafe. Let's say you walk into this beautiful Cafe, and order for a coffee. Based on your requirements, the chefs will gather all the ingredients and prepare a coffee for you.</p>
<p>Now this simple process involved the following parts:</p>
<ul>
<li><p>Ingredients</p>
</li>
<li><p>Actions performed by the chefs on the ingredients</p>
</li>
<li><p>Your coffee</p>
</li>
</ul>
<p>Similarly, in the context of programming, we have some input data (ingredients), and we want to get the output i.e. the final result (the coffee). In order to do that, it is required to perform certain actions on that input data (actions performed by the chefs).</p>
<p>Operators are the symbols that help us perform these actions. They are simply that glue, that help us put together some data, and generate some result. The simplest example would be:</p>
<pre><code class="language-javascript">5 + 2
</code></pre>
<p>Here, <code>+</code> is an operator, whose job is to sum up the numbers given to it.</p>
<hr />
<h2>Expressions</h2>
<p>Now that we have a basic idea about operators, we need to understand one more term, which is pretty common in programming languages. An expression is simply a valid unit of code that evaluates to a single value. This value can be a number, a string, a boolean value, a function, etc.</p>
<p>In our analogy, we can think of an expression like an "order". In order to complete an order, we use several ingredients, instructions given by the customer, etc., and in the end we put it all together, to create a final dish.</p>
<p>Example:</p>
<pre><code class="language-javascript">5 + 2
</code></pre>
<p>This is a very simple expression. It produces the value <code>7</code>.</p>
<p>Here,</p>
<ul>
<li><p><code>5</code> &amp; <code>2</code> are the operands</p>
</li>
<li><p><code>+</code> is the operator (just like we saw in the last section)</p>
</li>
<li><p><code>7</code> is the output produced</p>
</li>
</ul>
<h3>Structure of expressions</h3>
<p>Such expressions are built using operators. And we can use any valid combination of operators, to create any type of expression, no matter how simple or complex. A simple structure is given below:</p>
<img src="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/6530bc99-02d5-43c1-a830-55dfbbdd7ce8.png" alt="Diagram illustrating operators and operands using the expression 5 + 2 * 6, where + and * are operators and 5, 2, and 6 are operands." style="display:block;margin:0 auto" />

<hr />
<h2>Types of Operators in JavaScript</h2>
<p>Now that we understand what operators and expressions are, let's deep dive into the types of operators in JavaScript. Some of these concepts, even extend to other programming languages, since operators is a fundamental concept.</p>
<p>Following are the most commonly used types of operators in JavaScript:</p>
<ol>
<li><p>Arithmetic Operators</p>
</li>
<li><p>Comparison/Relational Operators</p>
</li>
<li><p>Logical Operators</p>
</li>
<li><p>Assignment Operators</p>
</li>
<li><p>Conditional/Ternary Operator</p>
</li>
</ol>
<hr />
<h2>Arithmetic Operators</h2>
<p>Arithmetic operators allow us to perform certain mathematical operations on data. Whenever we want to add, subtract, divide, multiply, etc. any values or variables, we make use of such arithmetic operators.</p>
<p>Think of them as how chefs add, remove, combine, etc. several ingredients to make dishes.</p>
<table>
<thead>
<tr>
<th>Operator</th>
<th>Meaning</th>
<th>Analogy</th>
</tr>
</thead>
<tbody><tr>
<td><code>+</code></td>
<td>Addition</td>
<td>Mix ingredients</td>
</tr>
<tr>
<td><code>-</code></td>
<td>Subtraction</td>
<td>Remove ingredients</td>
</tr>
<tr>
<td><code>*</code></td>
<td>Multiplication</td>
<td>Add an ingredient multiple times</td>
</tr>
<tr>
<td><code>/</code></td>
<td>Division</td>
<td>Split portions</td>
</tr>
<tr>
<td><code>%</code></td>
<td>Modulus</td>
<td>Find leftovers</td>
</tr>
<tr>
<td><code>**</code></td>
<td>Exponentiation</td>
<td>Multiply an ingredient multiple times</td>
</tr>
<tr>
<td><code>++</code></td>
<td>Increment</td>
<td>Add one extra ingredient</td>
</tr>
<tr>
<td><code>--</code></td>
<td>Decrement</td>
<td>Remove one ingredient</td>
</tr>
</tbody></table>
<h3>Example Code</h3>
<pre><code class="language-javascript">console.log(12 + 8);    // 20
console.log(15 - 6);    // 9
console.log(4 * 5);     // 20
console.log(20 / 4);    // 5
console.log(14 % 4);    // 2
console.log(3 ** 4);    // 81

let count = 10;
count++;
console.log(count);     // 11

count--;
console.log(count);     // 10
</code></pre>
<hr />
<h2>Comparison/Relational Operators</h2>
<p>If arithmetic operators are like preparing ingredients, then comparison operators are like checking ingredients before cooking.</p>
<p>Comparison operators, often referred to as Relational operators, allow us to compare data in our program. These always return a boolean value (<code>true</code> or <code>false</code>). These are very useful when writing conditional statements.</p>
<table>
<thead>
<tr>
<th>Operator</th>
<th>Meaning</th>
<th>Analogy</th>
</tr>
</thead>
<tbody><tr>
<td><code>==</code></td>
<td>Equal to</td>
<td>Check if two ingredients look the same</td>
</tr>
<tr>
<td><code>===</code></td>
<td>Strict equal to</td>
<td>Check if two ingredients are exactly the same</td>
</tr>
<tr>
<td><code>!=</code></td>
<td>Not equal to</td>
<td>Check if two ingredients are different</td>
</tr>
<tr>
<td><code>!==</code></td>
<td>Strict not equal to</td>
<td>Check if two ingredients are completely different</td>
</tr>
<tr>
<td><code>&gt;</code></td>
<td>Greater than</td>
<td>Check which ingredient quantity is larger</td>
</tr>
<tr>
<td><code>&lt;</code></td>
<td>Less than</td>
<td>Check which ingredient quantity is smaller</td>
</tr>
<tr>
<td><code>&gt;=</code></td>
<td>Greater than or equal to</td>
<td>Check if an ingredient quantity is at least a certain amount</td>
</tr>
<tr>
<td><code>&lt;=</code></td>
<td>Less than or equal to</td>
<td>Check if an ingredient quantity is at most a certain amount</td>
</tr>
</tbody></table>
<h3>Example Code</h3>
<pre><code class="language-javascript">console.log(10 &gt; 5);    // true
console.log(4 &lt; 2);     // false
console.log(7 &gt;= 7);    // true
console.log(3 &lt;= 6);    // true

console.log(8 == "8");  // true
console.log(8 === "8"); // false

console.log(5 != 3);    // true
console.log(5 !== "5"); // true
</code></pre>
<h3>Important: <code>==</code> and <code>===</code> are not the same</h3>
<p>JavaScript has two operators for checking equality, and understanding their difference is extremely important.</p>
<p>The <code>==</code> operator checks if two values are equal, while ignoring their data types. In other words, it only cares about values, not the data types.</p>
<pre><code class="language-javascript">console.log(5 == 5);        // true     -&gt;     this makes sense
console.log(5 == "5");      // true     -&gt;     weird
</code></pre>
<p>If you've ever studied any other language, the above example might look weird. But the simple reason is, the <code>==</code> operator does not care about the data types.</p>
<p>On the other hand, the <code>===</code> operator does. It is called strict equality, and it checks both, values, as well as the data types.</p>
<pre><code class="language-javascript">console.log(5 === "5")    // false    -&gt;    now it makes sense
</code></pre>
<p>Think of <code>==</code> as a casual comparison, and <code>===</code> as a strict comparison.</p>
<h3>Recommendation</h3>
<p>In most cases, prefer using <code>===</code> instead of <code>==</code>. It avoids unexpected type conversions, and makes code more predictable in general.</p>
<hr />
<h2>Logical Operators</h2>
<p>Logical operators represent decisions the chef makes before cooking.</p>
<table>
<thead>
<tr>
<th>Operator</th>
<th>Meaning</th>
<th>Analogy</th>
</tr>
</thead>
<tbody><tr>
<td><code>&amp;&amp;</code></td>
<td>Logical AND</td>
<td>Cook the dish only if all ingredients are available</td>
</tr>
<tr>
<td><code>||</code></td>
<td>Logical OR</td>
<td>Cook the dish if atleast one ingredient is available</td>
</tr>
<tr>
<td><code>!</code></td>
<td>Logical NOT</td>
<td>Check if an ingredient is not available</td>
</tr>
</tbody></table>
<p>Just like Comparison operators, Logical operators also return boolean values. They help us combine multiple conditions together.</p>
<h3>Example Code</h3>
<pre><code class="language-javascript">let hasFlour = true;
let hasSugar = false;

console.log(hasFlour &amp;&amp; hasSugar);  // false
console.log(hasFlour || hasSugar);  // true
console.log(!hasFlour);             // false
</code></pre>
<h3>Truth Tables</h3>
<p>Truth Tables simply allow us to look at all the possible outputs that a logical operator can produce based on the inputs.</p>
<h3>Truth Table for Logical AND</h3>
<table>
<thead>
<tr>
<th>Input <code>A</code></th>
<th>Input <code>B</code></th>
<th><code>A &amp;&amp; B</code></th>
</tr>
</thead>
<tbody><tr>
<td>true</td>
<td>true</td>
<td>true</td>
</tr>
<tr>
<td>true</td>
<td>false</td>
<td>false</td>
</tr>
<tr>
<td>false</td>
<td>true</td>
<td>false</td>
</tr>
<tr>
<td>false</td>
<td>false</td>
<td>false</td>
</tr>
</tbody></table>
<p>It evaluates to <code>true</code>, only if both inputs are <code>true</code>. In all the other cases, it evaluates to <code>false</code>.</p>
<h3>Truth Table for Logical OR</h3>
<table>
<thead>
<tr>
<th>Input <code>A</code></th>
<th>Input <code>B</code></th>
<th><code>A || B</code></th>
</tr>
</thead>
<tbody><tr>
<td>true</td>
<td>true</td>
<td>true</td>
</tr>
<tr>
<td>true</td>
<td>false</td>
<td>true</td>
</tr>
<tr>
<td>false</td>
<td>true</td>
<td>true</td>
</tr>
<tr>
<td>false</td>
<td>false</td>
<td>false</td>
</tr>
</tbody></table>
<p>It evaluates to <code>false</code>, only if both inputs are <code>false</code>. In all the other cases, it evaluates to <code>true</code>.</p>
<h3>Truth Table for Logical NOT</h3>
<table>
<thead>
<tr>
<th>Input <code>A</code></th>
<th><code>!A</code></th>
</tr>
</thead>
<tbody><tr>
<td>true</td>
<td>false</td>
</tr>
<tr>
<td>false</td>
<td>true</td>
</tr>
</tbody></table>
<p>It simply flips the value. <code>true</code> becomes <code>false</code>, and <code>false</code> becomes <code>true</code>.</p>
<hr />
<h2>Assignment Operators</h2>
<p>Assignment operators are simply used to store values in variables and update them later. In assignment operators, we have the simple <code>=</code> assignment operator, that assigns the value on the right-hand side, to the variable on the left-hand side.</p>
<p>However in addition to this, we also have several compound assignment operators. These include <code>+=</code>, <code>-=</code>, <code>*=</code>, etc. These are just shorthands for longer assignment statements. In other words, <code>a += 5</code> is the same as <code>a = a + 5</code>.</p>
<p>As per our analogy, think of assignment operators like writing ingredients on a recipe board and modifying them as you cook.</p>
<table>
<thead>
<tr>
<th>Operator</th>
<th>Meaning</th>
<th>Analogy</th>
</tr>
</thead>
<tbody><tr>
<td><code>=</code></td>
<td>Assignment</td>
<td>Write an ingredient on the recipe board</td>
</tr>
<tr>
<td><code>+=</code></td>
<td>Add and assign</td>
<td>Add more of an ingredient to the recipe</td>
</tr>
<tr>
<td><code>-=</code></td>
<td>Subtract and assign</td>
<td>Remove some quantity of an ingredient</td>
</tr>
<tr>
<td><code>*=</code></td>
<td>Multiply and assign</td>
<td>Increase the recipe quantity multiple times</td>
</tr>
<tr>
<td><code>/=</code></td>
<td>Divide and assign</td>
<td>Split the ingredient quantity</td>
</tr>
<tr>
<td><code>%=</code></td>
<td>Modulus and assign</td>
<td>Store the leftover quantity</td>
</tr>
<tr>
<td><code>**=</code></td>
<td>Exponentiation and assign</td>
<td>Multiply the ingredient by itself multiple times</td>
</tr>
</tbody></table>
<h3>Example Code</h3>
<pre><code class="language-javascript">let quantity = 4;
console.log(quantity);      // 4

quantity += 3;
console.log(quantity);      // 7

quantity -= 2;
console.log(quantity);      // 5

quantity *= 2;
console.log(quantity);      // 10

quantity /= 5;
console.log(quantity);      // 2

quantity %= 2;
console.log(quantity);      // 0

quantity = 3;
quantity **= 2;
console.log(quantity);      // 9
</code></pre>
<hr />
<h2>Conditional/Ternary Operator</h2>
<p>The conditional (ternary) operator is a shorter way to write simple <code>if...else</code> conditions. It chooses between two values based on whether a condition is true or false.</p>
<pre><code class="language-javascript">condition ? valueIfTrue : valueIfFalse
</code></pre>
<p>As per our analogy, you can think of it as choosing between two dishes based on available ingredients. If chocolate is available, make a chocolate cake, otherwise make a vanilla cake.</p>
<h3>Example Code</h3>
<pre><code class="language-javascript">let age = 18;

let message = age &gt;= 18 ? "You can enter" : "Entry not allowed";

console.log(message);   // You can enter
</code></pre>
<hr />
<h2>Conclusion</h2>
<p>JavaScript operators are the building blocks that allow us to perform calculations, compare values and make decisions in our programs. We looked at some of the most popular operators in this article, such as the conditional operator, arithmetic, comparison, logical, and assignment.</p>
<p>You will eventually feel more at ease utilizing operators in real-world code if you continue experimenting with small examples and try combining various operators.</p>
]]></content:encoded></item><item><title><![CDATA[Arrow Functions in JavaScript: Write Less, Mean More]]></title><description><![CDATA[Introduction
If you've been writing JavaScript for a while, you've almost certainly run into this kind of code:
function add(a, b) {
    return a + b;
}

Nothing wrong with it. But modern JavaScript g]]></description><link>https://blog.sameerbhagtani.dev/arrow-functions-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/arrow-functions-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[functions]]></category><category><![CDATA[ Arrow Functions In JavaScript]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Sat, 07 Mar 2026 13:54:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/13f40a98-72ee-4ba7-aece-4f311efa5e80.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2>Introduction</h2>
<p>If you've been writing JavaScript for a while, you've almost certainly run into this kind of code:</p>
<pre><code class="language-javascript">function add(a, b) {
    return a + b;
}
</code></pre>
<p>Nothing wrong with it. But modern JavaScript gives you a shorter way to write the same thing, and once you get used to it, going back feels like putting on a heavy coat. Arrow functions cut the boilerplate and make your code easier to scan at a glance.</p>
<hr />
<h2>What Arrow Functions Are</h2>
<p>Arrow functions are a shorter syntax for writing functions in JavaScript. They were introduced in ES6 (2015) and have become the default style in most modern codebases.</p>
<p>They're not a replacement for every function you'll ever write. But for simple operations, callbacks, and one-liners, they're cleaner.</p>
<hr />
<h2>Basic Syntax</h2>
<p>Here's the same <code>add</code> function rewritten as an arrow function:</p>
<pre><code class="language-javascript">const add = (a, b) =&gt; {
    return a + b;
};
</code></pre>
<p>Instead of the <code>function</code> keyword, you write the parameters in parentheses, then <code>=&gt;</code>, then the function body. That <code>=&gt;</code> is the "arrow" in arrow function.</p>
<p>The structure is:</p>
<pre><code class="language-javascript">const functionName = (parameters) =&gt; {
    // body
};
</code></pre>
<hr />
<h2>One Parameter</h2>
<p>When your function takes exactly one parameter, you can drop the parentheses:</p>
<pre><code class="language-javascript">// Normal function
function greet(name) {
    return "Hello, " + name;
}

// Arrow function
const greet = name =&gt; {
    return "Hello, " + name;
};
</code></pre>
<p>Both do the same thing. The arrow version just skips the parens around <code>name</code>.</p>
<p>If there are zero parameters or two or more, the parentheses come back:</p>
<pre><code class="language-javascript">const sayHi = () =&gt; {
    return "Hi!";
};
</code></pre>
<hr />
<h2>Multiple Parameters</h2>
<p>Two or more parameters always need parentheses:</p>
<pre><code class="language-javascript">// Normal function
function multiply(a, b) {
    return a * b;
}

// Arrow function
const multiply = (a, b) =&gt; {
    return a * b;
};
</code></pre>
<p>Same result, slightly less to type.</p>
<hr />
<h2>Implicit Return vs Explicit Return</h2>
<p>This is where arrow functions really start to pull ahead.</p>
<p>When your function body is a single expression, you can skip the curly braces and the <code>return</code> keyword. JavaScript will return the value automatically. This is called an implicit return.</p>
<pre><code class="language-javascript">// Explicit return (with curly braces)
const square = (n) =&gt; {
    return n * n;
};

// Implicit return (no curly braces, no return keyword)
const square = (n) =&gt; n * n;
</code></pre>
<p>Both versions return <code>n * n</code>. The second one just states it directly.</p>
<p>A few more examples:</p>
<pre><code class="language-javascript">const double = n =&gt; n * 2;

const greet = name =&gt; "Hello, " + name;

const add = (a, b) =&gt; a + b;
</code></pre>
<p>Clean and readable. You can tell at a glance what each function does.</p>
<p>One thing to watch out for: if you're returning an object literal, wrap it in parentheses. Otherwise JavaScript reads the curly braces as a function body, not an object.</p>
<pre><code class="language-javascript">// This breaks
const getUser = () =&gt; { name: "Alex" };

// This works
const getUser = () =&gt; ({ name: "Alex" });
</code></pre>
<p>The outer parentheses tell JS "this is an expression, not a block."</p>
<hr />
<h2>Arrow Functions vs Normal Functions</h2>
<p>The most obvious difference is syntax. But there's one behavioral difference worth knowing early: arrow functions don't have their own <code>this</code>.</p>
<p>You don't need to dig into <code>this</code> deeply right now. For simple tasks like math operations, string manipulation, and short callbacks, arrow functions work exactly the same as regular functions.</p>
<p>Here's a quick side-by-side:</p>
<pre><code class="language-javascript">// Normal function
function add(a, b) {
    return a + b;
}

// Arrow function
const add = (a, b) =&gt; a + b;
</code></pre>
<pre><code class="language-javascript">// Normal function with no parameters
function sayHello() {
    return "Hello!";
}

// Arrow function with no parameters
const sayHello = () =&gt; "Hello!";
</code></pre>
<pre><code class="language-javascript">// Normal function, one parameter
function double(n) {
    return n * 2;
}

// Arrow function, one parameter
const double = n =&gt; n * 2;
</code></pre>
<p>The pattern is consistent. Strip <code>function</code>, move the parameters to the left of <code>=&gt;</code>, and if it's a single expression, drop the braces and <code>return</code>.</p>
<hr />
<h2>When to Use Arrow Functions</h2>
<p>Arrow functions work well for:</p>
<ul>
<li><p>Short utility functions (<code>add</code>, <code>double</code>, <code>greet</code>)</p>
</li>
<li><p>Callbacks in array methods like <code>map</code>, <code>filter</code>, and <code>reduce</code></p>
</li>
<li><p>Any place where you want concise, readable code</p>
</li>
</ul>
<p>For longer functions, functions that need their own <code>this</code>, or constructors, regular functions are still the right call. Arrow functions are a tool, not a universal replacement.</p>
<p>But for the majority of functions you write day to day? The arrow syntax keeps things clean, reduces visual noise, and reads more like math than ceremony.</p>
<hr />
<h2>Summary</h2>
<pre><code class="language-javascript">// Zero parameters
const sayHi = () =&gt; "Hi!";

// One parameter (parens optional)
const double = n =&gt; n * 2;

// Multiple parameters
const add = (a, b) =&gt; a + b;

// Multi-line body (needs curly braces and return)
const greet = (name) =&gt; {
    const message = "Hello, " + name;
    return message;
};

// Returning an object
const getUser = () =&gt; ({ name: "Alex", age: 30 });
</code></pre>
<p>Once the syntax clicks, you'll start seeing arrow functions everywhere in modern JavaScript code. And you'll probably start writing them that way too.</p>
]]></content:encoded></item><item><title><![CDATA[Control Flow in JavaScript: if, else, and switch Explained]]></title><description><![CDATA[Every program makes decisions. Should this user see the dashboard or the login page? Did the student pass or fail? Is this item in stock? Code that just runs top to bottom, line by line, without react]]></description><link>https://blog.sameerbhagtani.dev/control-flow-in-javascript</link><guid isPermaLink="true">https://blog.sameerbhagtani.dev/control-flow-in-javascript</guid><category><![CDATA[ChaiCode]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[control flow]]></category><category><![CDATA[Web Development]]></category><dc:creator><![CDATA[Sameer Bhagtani]]></dc:creator><pubDate>Thu, 05 Mar 2026 05:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/695033c2b374c95f620094a1/4fedbb52-9bd3-432b-ac6d-28fca69dc751.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Every program makes decisions. Should this user see the dashboard or the login page? Did the student pass or fail? Is this item in stock? Code that just runs top to bottom, line by line, without reacting to anything is not very useful. Control flow is what lets your program look at a situation and do something appropriate.</p>
<p>In JavaScript, control flow mostly comes down to a handful of constructs: <code>if</code>, <code>if-else</code>, <code>else if</code>, and <code>switch</code>. They're not complicated, but the small differences between them matter more than most beginners expect.</p>
<hr />
<h2>What "Control Flow" Actually Means</h2>
<p>When JavaScript runs your code, it starts at the top and works its way down. Control flow is anything that changes that path. A condition is evaluated, and depending on the result, the program either enters a block of code or skips it.</p>
<p>Think of it like a security checkpoint. The guard checks your ID. If you're old enough, you get in. If not, you don't. The program doesn't do both things. It picks one path and follows it.</p>
<p>That's it. Everything else is just syntax.</p>
<hr />
<h2>The <code>if</code> Statement</h2>
<p>The <code>if</code> statement is the simplest form of control flow. It runs a block of code only when a condition is true. If the condition is false, the block is skipped entirely.</p>
<pre><code class="language-javascript">let age = 20;

if (age &gt;= 18) {
  console.log("You can vote.");
}
</code></pre>
<p>Here, JavaScript checks whether <code>age &gt;= 18</code> is true. It is (20 is greater than 18), so it prints the message.</p>
<p>Change <code>age</code> to 15 and nothing prints. The condition fails, the block is skipped, and execution continues after the closing brace.</p>
<p>One thing worth noting: the condition inside <code>if()</code> gets converted to a boolean. Values like <code>0</code>, <code>""</code>, <code>null</code>, <code>undefined</code>, <code>NaN</code>, and <code>false</code> are all falsy in JavaScript. Everything else is truthy. This matters when you're checking variables that might be empty or unset.</p>
<hr />
<h2>The <code>if-else</code> Statement</h2>
<p>Sometimes you want something to happen either way. If the condition is true, do this. If it's false, do that instead. That's <code>if-else</code>.</p>
<pre><code class="language-javascript">let marks = 45;

if (marks &gt;= 50) {
  console.log("Pass");
} else {
  console.log("Fail");
}
</code></pre>
<p>Only one of those two blocks will ever run. JavaScript evaluates the condition, takes the true branch or the false branch, and moves on.</p>
<p>This is cleaner than writing two separate <code>if</code> statements that check opposite conditions. It also signals intent: these two outcomes are mutually exclusive.</p>
<hr />
<h2>The <code>else if</code> Ladder</h2>
<p>Real situations often have more than two outcomes. A student doesn't just pass or fail. They might get an A, B, C, or fail. That's where <code>else if</code> comes in.</p>
<pre><code class="language-javascript">let marks = 72;

if (marks &gt;= 90) {
  console.log("Grade: A");
} else if (marks &gt;= 75) {
  console.log("Grade: B");
} else if (marks &gt;= 60) {
  console.log("Grade: C");
} else {
  console.log("Grade: F");
}
</code></pre>
<p>JavaScript checks each condition from top to bottom. The moment one is true, it runs that block and skips everything below it. So if <code>marks</code> is 72, the first two conditions fail and the third one passes. It prints <code>Grade: C</code> and stops.</p>
<p>This order matters. If you accidentally put a broader condition above a narrower one, the narrower one may never get a chance to run. For example, if you put <code>marks &gt;= 60</code> before <code>marks &gt;= 75</code>, any mark above 60 would always match the first condition and never reach the second.</p>
<p>The final <code>else</code> at the bottom acts as a catch-all. It runs when none of the conditions above are true. You don't have to include it, but it's good practice when you want to handle unexpected cases.</p>
<hr />
<h2>The <code>switch</code> Statement</h2>
<p>The <code>switch</code> statement is a different approach to branching. Instead of writing a chain of conditions, you give it a single value and match it against specific cases.</p>
<pre><code class="language-javascript">let day = "Monday";

switch (day) {
  case "Saturday":
  case "Sunday":
    console.log("Weekend");
    break;
  case "Monday":
    console.log("Start of the work week");
    break;
  case "Friday":
    console.log("Almost there");
    break;
  default:
    console.log("Midweek");
}
</code></pre>
<p>JavaScript evaluates <code>day</code>, finds the matching <code>case</code>, runs the code there, and stops at <code>break</code>.</p>
<h3>What <code>break</code> does</h3>
<p>Without <code>break</code>, JavaScript keeps executing the code in the next case, even if that case's value doesn't match. This is called "fall-through" and it causes bugs that are surprisingly hard to spot.</p>
<pre><code class="language-javascript">let color = "red";

switch (color) {
  case "red":
    console.log("Red");
  case "blue":
    console.log("Blue");   // This also runs if break is missing above
  default:
    console.log("Other");  // And this
}
</code></pre>
<p>Without <code>break</code> after <code>"red"</code>, all three lines print. With it, only <code>"Red"</code> prints. Always include <code>break</code> unless you intentionally want fall-through (which is rare, and usually worth a comment when you do it).</p>
<p>The <code>default</code> case is like <code>else</code>. It runs when nothing matches.</p>
<hr />
<h2>When to Use <code>switch</code> vs <code>if-else</code></h2>
<p>This comes up a lot and the honest answer is: it depends on what you're comparing.</p>
<p>Use <code>if-else</code> when:</p>
<ul>
<li><p>You're checking ranges or inequalities (<code>age &gt;= 18</code>, <code>score &lt; 50</code>)</p>
</li>
<li><p>Your conditions involve different variables or complex expressions</p>
</li>
<li><p>You only have two or three branches</p>
</li>
</ul>
<p>Use <code>switch</code> when:</p>
<ul>
<li><p>You're comparing one variable against several fixed values</p>
</li>
<li><p>You have many possible cases and readability is getting messy with <code>else if</code></p>
</li>
<li><p>The values are strings or numbers with discrete, known options</p>
</li>
</ul>
<p>Compare these two versions of the same logic:</p>
<pre><code class="language-javascript">// if-else
if (status === "active") {
  activate();
} else if (status === "inactive") {
  deactivate();
} else if (status === "pending") {
  showPending();
} else {
  showError();
}
</code></pre>
<pre><code class="language-javascript">// switch
switch (status) {
  case "active":
    activate();
    break;
  case "inactive":
    deactivate();
    break;
  case "pending":
    showPending();
    break;
  default:
    showError();
}
</code></pre>
<p>The <code>switch</code> version is easier to scan. You can see all the possible values at a glance. The <code>if-else</code> version looks fine here but starts to get crowded with six or seven branches.</p>
<p>That said, <code>if-else</code> is more flexible. You can't use ranges in a <code>switch</code> case. <code>case marks &gt;= 90</code> is not valid syntax. For anything involving comparisons, stick with <code>if-else</code>.</p>
<hr />
<h2>A Practical Example</h2>
<p>Here's a small program that uses both, so you can see them side by side in realistic code:</p>
<pre><code class="language-javascript">let age = 17;
let memberType = "student";

if (age &lt; 18) {
  console.log("Minor: parental consent required");
} else {
  console.log("Adult: no restrictions");
}

switch (memberType) {
  case "student":
    console.log("50% discount applied");
    break;
  case "senior":
    console.log("30% discount applied");
    break;
  case "regular":
    console.log("No discount");
    break;
  default:
    console.log("Unknown member type");
}
</code></pre>
<p>The <code>if-else</code> handles the age check because it's a range comparison. The <code>switch</code> handles the member type because it's matching one variable against known string values.</p>
<hr />
<h2>Conclusion</h2>
<p>Control flow is not a difficult topic, but getting comfortable with it takes some practice. The syntax becomes second nature quickly. What takes longer is developing the instinct for which construct fits the situation. Once you stop thinking about syntax and start thinking about what the program needs to decide, it gets easier.</p>
]]></content:encoded></item></channel></rss>