🍪

Cookies! Although those a little less delicious... I am using them to analyze site traffic. By continuing to use this site you consent to the Google Cookies Policy

JavaScript — The 'var' and 'let' keywords story in declaring a non-constant variables

In JavaScript, both let and var can be used for declaring non-constant variables. While let is widely used in modern JavaScript and is the recommended keyword for declaring non-constant variables, it may be confusing why var even exists and how variables declared with var differ from those declared with let.

Long-short story about var and let

The var keyword has been a fundamental part of JavaScript. It is function-scoped, meaning that variables declared with it are accessible throughout the entire function, regardless of block scope.

When JavaScript was first introduced in the mid-1990s, it was primarily used for simple scripting tasks on web pages. As time flew by, businesses evolved and defined much higher expectations, constantly adding complexity and expecting more advanced features. This made the usage of var much less predictable. Due to the lack of mentioned block scope, it often led to unintended variable hoisting and potential bugs.

With the introduction of ES6 (ECMAScript 2015) in 2015, JavaScript introduced the let keyword to address these issues. It came with block scoping, meaning that variables declared with them are only accessible within the block (e.g., within loops, if statements, or any code block enclosed by curly braces). This improved scoping behavior made it easier to reason about variable lifetimes and lowered the probability of unintended side effects.

A common question might be: "So, why does the var keyword still exist?" The answer is backward compatibility. There is a lot of legacy code making use of var, and it cannot simply stop working.

The var and let variables in head to head comparison

Scope

  • Variables declared with var are function-scoped. This means they are accessible throughout the function in which they are declared, regardless of block scope.

  • Variables declared with let are block-scoped. They are only accessible within the block in which they are defined (e.g., inside loops, if statements, or any code block enclosed by curly braces {}).

function testScope() {
  if (true) {
    var testVar = "I'm var!";
    let testLet = "I'm let!";
  }

   console.log(testVar); // I'm var!
   console.log(testLet); // ReferenceError: testLet is not defined
}

testScope();

Hoisting

  • Variables declared with var are hoisted to the top of their function or global scope. This means you can access the variable before it's declared in the code, but its value will be undefined.

  • Variables declared with let are hoisted to the top of their block scope, but they are not initialized. Accessing the variable before its declaration results in a ReferenceError.

function testHoisting() {
  console.log(testVar); // undefined
  var testVar;
  
  console.log(testLet); // ReferenceError: Cannot access 'testLet' before initialization
  let testLet;
}

testHoisting();

Re-declaration

  • Variables declared with var can be re-declared within the same scope without any error.

  • Variables declared with let cannot be re-declared within the same scope. Attempting to do so will result in a SyntaxError.

function testRedeclaration() {
  var testVar = "";
  var testVar = "I'm var!";
  console.log(testVar); // I'm var!
  
  let testLet = "";
  let testLet = "I'm let!"; // SyntaxError: Identifier 'testLet' has already been declared
  console.log(testLet);
}

testRedeclaration();

Global Object Property

  • Variables declared with var become properties of the global object (window in browsers) if declared in the global scope.

  • Variables declared with let do not become properties of the global object, even if declared in the global scope. This helps in avoiding accidental global variable declarations, reducing potential naming conflicts.

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Test Global Object Property</title>
  </head>
  <body></body>

  <script>
    var testVar = "I'm var!";

    console.log(window.testVar); // I'm var!

    let testLet = "I'm let!";

    console.log(window.testLet); // undefined
  </script>
</html>

Conclusion

Both var and let are used for variable declaration in JavaScript, but they differ significantly in their behavior. var is function-scoped, hoisted to the top of its function or global scope, allows access before initialization, and permits variable re-declaration. On the other hand, let provides block-scoping, prohibits re-declaration, and prevents access before initialization, even though it is hoisted to the top of its block scope.

While var continues to exist for backward compatibility, as a best practice, prefer using let over var for variable declaration in modern JavaScript code. This helps improve code clarity, lowers the probability of bugs, and aligns with the latest language standards.

The code used in this blog is available on GitHub.