JavaScriptClean CodeBest PracticesES6

The Death of var and the Retirement of let

C
Clean Code Advocate
Featured Guide 10 min read

Delete var.

It hoists. It leaks scope. It's confusing. There is literally zero reason to use var in 2026. If you see it in a PR, reject it immediately.

The `var` Disaster

var doesn't respect code blocks. It "hoists" itself to the top of the function or global scope, leading to variables existing before you declare them.

// ❌ The Hoisting Nightmare
console.log(x); // undefined (Not ReferenceError!)
var x = 5;

if (true) {
  var y = 10;
}
console.log(y); // 10 (Leaked out of the if block!)

02. Avoid let

The `let` Trap

"But I need to change the value in a loop!"
Do you? Or do you actually need map() or reduce()?

Every time you use let, you introduce state mutation. The value changes over time. This forces your brain to track the state history of a variable as you read the code.

// ❌ Bad (Imperative Mutation)
let total = 0;
for (const x of items) {
  total += x.price; // State changes N times!
}

// ✅ Good (Declarative Expression)
const total = items.reduce((acc, x) => acc + x.price, 0);

Deep Dive: Temporal Dead Zone (TDZ)

Unlike var, which hoists as undefined, let and const hoist but are placed in the TDZ until the execution reaches their declaration line.

Accessing them early throws a ReferenceError. This "fail-fast" behavior prevents subtle bugs caused by using variables before they exist.

03. The const Kingdom

const is a signal to other developers: "This reference will never change." It reduces cognitive load. You define it, assign it, and trust it forever.

Comparison Table

Keyword Reassignable? Scope Verdict
var Yes Function DELETE
let Yes Block USE RARELY
const No Block DEFAULT

04. The Senior Engineer's Take

Reassignment != Mutation

Remember: const prevents reassignment, not mutation of the object content.
const x = [] means you can't say x = somethingElse, but you CAN say x.push(1).

For true immutability, use Object.freeze() or the new Records & Tuples.

Interactive Playground

import React, { useState } from 'react';

// 🔒 Const Visualizer

export default function ConstDemo() {
    return (
        <div className="bg-slate-50 dark:bg-slate-950 p-8 rounded-3xl border border-slate-200 dark:border-slate-800 shadow-xl">
             <div className="flex justify-between items-center mb-10">
                <h3 className="text-2xl font-black text-gray-900 dark:text-white flex items-center gap-3">
                    <span className="text-gray-500">🔒</span> Immutable Mindset
                </h3>
            </div>

            <div className="grid grid-cols-1 md:grid-cols-3 gap-6">
                
                <div className="p-6 bg-red-50 dark:bg-red-900/10 border border-red-200 dark:border-red-900/20 rounded-xl relative overflow-hidden group">
                    <div className="absolute top-4 right-4 text-red-300 group-hover:text-red-500 transition-colors">
                        <span className="text-3xl">🔓</span>
                    </div>
                    <div className="font-mono text-xl font-bold text-red-600 mb-2">var</div>
                    <p className="text-sm text-gray-600 dark:text-gray-400">
                        Function scoped. Hoisted. Can be re-declared.
                    </p>
                    <div className="mt-4 text-xs font-bold text-red-500 flex items-center gap-2">
                        <span>⚠️</span> DANGER: SCOPE LEAK
                    </div>
                </div>

                <div className="p-6 bg-yellow-50 dark:bg-yellow-900/10 border border-yellow-200 dark:border-yellow-900/20 rounded-xl relative overflow-hidden">
                     <div className="absolute top-4 right-4 text-yellow-300">
                        <span className="text-3xl">🔓</span>
                    </div>
                    <div className="font-mono text-xl font-bold text-yellow-600 mb-2">let</div>
                    <p className="text-sm text-gray-600 dark:text-gray-400">
                        Block scoped. Can be re-assigned. Use only for loop counters.
                    </p>
                     <div className="mt-4 text-xs font-bold text-yellow-600 opacity-60">
                        ACCEPTABLE: CONTROL FLOW
                    </div>
                </div>

                <div className="p-6 bg-green-50 dark:bg-green-900/10 border border-green-200 dark:border-green-900/20 rounded-xl relative overflow-hidden shadow-lg scale-105 ring-2 ring-green-500 ring-opacity-50">
                     <div className="absolute top-4 right-4 text-green-500">
                        <span className="text-3xl">🔒</span>
                    </div>
                    <div className="font-mono text-xl font-bold text-green-600 mb-2">const</div>
                    <p className="text-sm text-gray-600 dark:text-gray-400">
                        Block scoped. Cannot be re-assigned. The default choice.
                    </p>
                    <div className="mt-4 text-xs font-bold text-green-600 flex items-center gap-2">
                        <span></span> PREFERRED: 99%
                    </div>
                </div>

            </div>
        </div>
    );
}