DEV Community

vimuth
vimuth

Posted on

Understanding var and let in JavaScript: When and Why to Use Each for Cleaner Code

In JavaScript, variable declarations are fundamental, but choosing between var, let, and const can greatly impact code quality. Understanding when and why to use each helps create cleaner, more predictable code, essential for modern development.

var and let are both used to declare variables in JavaScript, but they have some key differences in how they handle scope, hoisting, and re-declaration.

Key Differences Between var and let

  1. Scope

    • var is function-scoped: When you declare a variable with var, it’s accessible throughout the entire function in which it’s declared.
    • let is block-scoped: Variables declared with let are only accessible within the block (e.g., {...}) where they are defined, making it safer to use in most cases.
  2. Hoisting

    • Both var and let are hoisted to the top of their scope, but let is in a Temporal Dead Zone (TDZ) until the line where it’s defined, meaning you cannot access it before its declaration.
    • var, on the other hand, is hoisted without the TDZ, so it’s accessible throughout its scope (though it will be undefined until its declaration).
  3. Re-declaration

    • var allows re-declaration of the same variable in the same scope, which can lead to unintended bugs.
    • let does not allow re-declaration in the same scope, helping avoid accidental overwrites.

Example 1: Scope Difference

function testVar() {
  var x = 10;
  if (true) {
    var x = 20;  // Same `x` in function scope, reassigns the outer `x`
    console.log("Inside if-block:", x);  // Output: 20
  }
  console.log("Outside if-block:", x);  // Output: 20 (still the same `x`)
}

testVar();
Enter fullscreen mode Exit fullscreen mode

With let:

function testLet() {
  let y = 10;
  if (true) {
    let y = 20;  // New `y` scoped to this block only
    console.log("Inside if-block:", y);  // Output: 20
  }
  console.log("Outside if-block:", y);  // Output: 10 (outer `y` is unchanged)
}

testLet();
Enter fullscreen mode Exit fullscreen mode

In the testVar function, var declares a single x for the entire function scope, so reassigning x inside the if block also changes it outside the block. With let, y inside the if block is a separate variable from y outside, preserving each y's value in its own scope.

Example 2: Hoisting Difference

function hoistVar() {
  console.log(x);  // Output: undefined (due to hoisting)
  var x = 10;
  console.log(x);  // Output: 10
}

hoistVar();
Enter fullscreen mode Exit fullscreen mode

With let:

function hoistLet() {
  console.log(y);  // Error: Cannot access 'y' before initialization
  let y = 10;
  console.log(y);  // This line would not be reached
}

hoistLet();
Enter fullscreen mode Exit fullscreen mode

In hoistVar, var x is hoisted to the top of the function scope, but it’s undefined until the actual assignment. In hoistLet, trying to access y before it’s assigned results in a ReferenceError because let variables are hoisted but remain in a Temporal Dead Zone (TDZ) until their declaration.

Example 3: Re-declaration

function redeclareVar() {
  var x = 5;
  var x = 10;  // Allowed with `var`
  console.log(x);  // Output: 10
}

redeclareVar();
Enter fullscreen mode Exit fullscreen mode

With let:

function redeclareLet() {
  let y = 5;
  let y = 10;  // Error: Identifier 'y' has already been declared
}

redeclareLet();
Enter fullscreen mode Exit fullscreen mode

With var, re-declaring x in the same scope is allowed, which could cause unintended bugs. With let, re-declaring y in the same scope results in an error, helping to avoid accidental overwrites.

Summary

  • Scope: var is function-scoped; let is block-scoped.
  • Hoisting: var is hoisted without restriction, while let is in a Temporal Dead Zone.
  • Re-declaration: var allows it; let does not.

In general, let is recommended in modern JavaScript because it provides more predictable scoping and reduces the risk of unintended bugs.

Top comments (0)