DEV Community

Cover image for JavaScript let vs var: A Beginner's Guide to Block Scoping
Satyam Gupta
Satyam Gupta

Posted on

JavaScript let vs var: A Beginner's Guide to Block Scoping

Blog Post: Let's Talk About let: Taming Variables in Modern JavaScript
If you've just started your journey into the wonderful, sometimes weird, world of JavaScript, you've probably met a bunch of characters: function, console.log, and of course, the humble var for creating variables.

For decades, var was the only way to declare a variable. It worked, but it had some... quirks. These quirks often led to confusing bugs and headaches for beginners and experts alike. It was like having a well-meaning but overly enthusiastic friend who sometimes helps you without being asked, causing more chaos than good.

Then, in 2015 (with ES6), JavaScript got a much-needed upgrade and introduced two new ways to declare variables: const and let. Today, we're going to have a heartfelt chat about let. We'll explore why it was created and how understanding it is a crucial step in writing clean, predictable, and professional-grade code.

The Quirks of var: Why We Needed a Change
To truly appreciate let, we need to understand what it was fixing. Let's look at the two biggest quirks of var.

  1. Function-Scoped, Not Block-Scoped

The most important concept to grasp is scope. Scope is simply: where is this variable available to use?

A var variable is function-scoped. This means it is only confined to the function it's declared in. If it's not declared inside a function, it's globally scoped (available everywhere). It doesn't care about if statements, for loops, or while loops. Those curly braces {} don't create a new scope for var.

Let's see this in action:

javascript
if (true) {
var message = "Hello from inside the if block!";
console.log(message); // "Hello from inside the if block!"
}

console.log(message); // "Hello from inside the if block!" (Wait, what?!)
See? The variable message happily exists outside the if block. This can be problematic because you might accidentally overwrite a variable you didn't mean to.

  1. Hoisting and The Weirdness of undefined

Hoisting is a JavaScript behavior where variable and function declarations are moved to the top of their containing scope during the compilation phase. With var, this leads to a strange situation.

javascript
console.log(myName); // Outputs: undefined (not an error!)
var myName = "Alice";
console.log(myName); // Outputs: "Alice"
It doesn't throw a ReferenceError! It's as if we wrote:

javascript
var myName; // Declaration is "hoisted" to the top and initialized with undefined
console.log(myName); // undefined
myName = "Alice"; // Assignment happens here
console.log(myName); // "Alice"
This is counter-intuitive. Trying to use a variable before it's declared should probably be an error, right?

Enter let: The Block-Scoped Hero
The let keyword was introduced to solve these exact problems. It makes variables behave in a way that most other programming languages do, which is more logical and less error-prone.

  1. let is Block-Scoped

A block is any code within a pair of curly braces {}—like an if statement, a for loop, or a while loop. A let variable is confined to the block it is declared in.

Let's revisit our first example with let:

javascript
if (true) {
let message = "Hello from inside the if block!";
console.log(message); // "Hello from inside the if block!"
}

console.log(message); // ReferenceError: message is not defined
Hooray! Now we get a clean, clear error. The variable message doesn't exist outside the block it was born in. This prevents accidental pollution of the wider scope and makes our code's intent much clearer. If a variable is only needed inside a loop, it should live and die inside that loop.

  1. let and The Temporal Dead Zone (TDZ)

let variables are also hoisted, but in a different, safer way. They are not initialized with undefined. The time between the start of the block and the point where the variable is declared is called the Temporal Dead Zone (TDZ). Accessing the variable in this zone will result in a ReferenceError.

javascript
console.log(favoriteFood); // ReferenceError: Cannot access 'favoriteFood' before initialization
let favoriteFood = "Pizza";
This is a good thing! The error is immediate and clear, making it much easier to debug and reason about your code. It forces us to write code in a more structured, top-down way.

let in Loops: A Classic Problem Solved
This is perhaps the most practical example of why let is a lifesaver. Consider a classic interview question:

javascript
// Using var (the old way)
for (var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // What will this output?
}, 100);
}
// Output: 3, 3, 3
Why 3? Because var is function-scoped. There's only one i shared by all three iterations of the loop and the setTimeout callback. By the time the callback runs, the loop has finished, and i is equal to 3.

Now, try it with let:

javascript
// Using let (the modern way)
for (let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i); // What will this output?
}, 100);
}
// Output: 0, 1, 2
It works! This is because let is block-scoped. A new i is created for each iteration of the loop. Each setTimeout callback holds a reference to its own separate i with the correct value. This removes a huge source of confusion for developers learning about closures and asynchronous code.

So, When Should I Use What?
Here’s a simple rule of thumb we teach our students at CoderCrafter:

Use const by default. If you know the value of a variable will not be reassigned, use const. It makes your code more predictable and prevents accidental reassignments.

Use let when you need to reassign a variable. If you know the value will change (like a counter in a loop), let is the correct choice.

Avoid using var. There's essentially no need to use var in modern JavaScript projects anymore. Consider it a piece of history, a reminder of how far the language has come.

Wrapping Up
Understanding the difference between var and let isn't just about memorizing syntax; it's about understanding scope, writing safer code, and thinking like a modern JavaScript developer. Embracing let and const is a sign that you're moving past basic scripting and into serious software development.

These core concepts of scope, hoisting, and closures form the bedrock of JavaScript. Mastering them is non-negotiable for anyone looking to build robust web applications.

If this deep dive into JavaScript fundamentals excites you, there's so much more to explore! The world of full-stack development is vast and incredibly rewarding. At CoderCrafter, our immersive Full Stack Development and MERN Stack Courses are designed to take you from absolute beginner to job-ready developer. We don't just teach you syntax; we teach you the why behind the code, helping you build a strong foundation for a successful career in tech.

Ready to conquer JavaScript and build amazing things? Visit codercrafter.in today to explore our courses and enroll in your future!

Top comments (0)