paint-brush
Why Does JavaScript Have 3 Ways to Declare Variables: Var, Let, and Constby@kirmani
139 reads

Why Does JavaScript Have 3 Ways to Declare Variables: Var, Let, and Const

by KirmaniAugust 12th, 2024
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

JavaScript offers three distinct ways to declare variables: `var, `let, and `const. Each serves a unique purpose, and understanding their differences is key to writing efficient and bug-free code. Let's delve into these keywords, explore their distinctions, discuss best practices, and debunk common myths.
featured image - Why Does JavaScript Have 3 Ways to Declare Variables: Var, Let, and Const
Kirmani HackerNoon profile picture

JavaScript, a language known for its flexibility, offers three distinct ways to declare variables: var, let, and const. Each serves a unique purpose, and understanding their differences is key to writing efficient and bug-free code. Let's delve into these keywords, explore their distinctions, discuss best practices, and debunk common myths and misconceptions.

The Basics

  • var: The original way to declare variables in JavaScript, var is function-scoped or globally scoped if declared outside a function. Variables declared with var are hoisted to the top of their scope, meaning they can be referenced before their declaration.
  • let: Introduced in ES6, let is block-scoped and not hoisted in the same manner as var. This makes its behavior more predictable.
  • const: Also introduced in ES6, const is block-scoped like let, but it is used to declare variables that should not be reassigned. However, const does not make the value immutable if the variable holds a reference to an object.


Lets have a look at the differences with some examples:

Scope

  • var is function-scoped, accessible throughout the function.
  • let and const are block-scoped, accessible only within the block they are defined in.

Example:

function scopeTest() {
    if (true) {
        var varVariable = 'I am a var';
        let letVariable = 'I am a let';
        const constVariable = 'I am a const';
    }
    console.log(varVariable); // 'I am a var'
    console.log(letVariable); // ReferenceError: letVariable is not defined
    console.log(constVariable); // ReferenceError: constVariable is not defined
}
scopeTest();

Hoisting

  • var is hoisted and initialized with undefined.
  • let and const are hoisted but not initialized, resulting in a ReferenceError if accessed before their declaration.

Example:

console.log(varVariable); // undefined
console.log(letVariable); // ReferenceError: Cannot access 'letVariable' before initialization
console.log(constVariable); // ReferenceError: Cannot access 'constVariable' before initialization

var varVariable = 'I am a var';
let letVariable = 'I am a let';
const constVariable = 'I am a const';

Re-declaration:

  • var can be re-declared within the same scope without errors.
  • let and const cannot be re-declared within the same scope.

Example:

var varVariable = 'I am a var';
var varVariable = 'I am another var'; // No error

let letVariable = 'I am a let';
let letVariable = 'I am another let'; // SyntaxError: Identifier 'letVariable' has already been declared

const constVariable = 'I am a const';
const constVariable = 'I am another const'; // SyntaxError: Identifier 'constVariable' has already been declared


Re-assignment:

  • var and let can be reassigned.
  • const cannot be reassigned after its initial declaration.

Example:

var varVariable = 'I am a var';
varVariable = 'I can be reassigned';

let letVariable = 'I am a let';
letVariable = 'I can also be reassigned';

const constVariable = 'I am a const';
constVariable = 'I cannot be reassigned'; // TypeError: Assignment to constant variable.

Global Object Property

  • var creates a property on the global window object.
  • let and const do not create properties on the global window object.

Example:

var varVariable = 'I am a var';
console.log(window.varVariable); // 'I am a var'

let letVariable = 'I am a let';
console.log(window.letVariable); // undefined

const constVariable = 'I am a const';
console.log(window.constVariable); // undefined

Block Scope with Loops

  • var does not create a new scope for each iteration, so the i variable is shared.
  • let creates a new scope for each iteration, so the j variable is unique to each iteration.

Example:

for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 1000); // 3, 3, 3
}

for (let j = 0; j < 3; j++) {
    setTimeout(() => console.log(j), 1000); // 0, 1, 2
}

Temporal Dead Zone

  • let and const are in a "temporal dead zone" from the start of the block until their declaration, meaning they cannot be accessed before they are declared.

Example:

console.log(letVariable); // ReferenceError: Cannot access 'letVariable' before initialization
let letVariable = 'I am a let';

console.log(constVariable); // ReferenceError: Cannot access 'constVariable' before initialization
const constVariable = 'I am a const';

Function Scope

  • var is function-scoped, so it is the same variable inside and outside the if block.
  • let is block-scoped, so it is a different variable inside and outside the if block.

Example:

function varTest() {
    var x = 1;
    if (true) {
        var x = 2; // same variable
        console.log(x); // 2
    }
    console.log(x); // 2
}
varTest();

function letTest() {
    let x = 1;
    if (true) {
        let x = 2; // different variable
        console.log(x); // 2
    }
    console.log(x); // 1
}
letTest();

Constants with Objects and Arrays

  • const allows mutation of objects and arrays but does not allow reassignment of the object reference.

Objects Example:

const constObj = { key: 'value' };
constObj.key = 'newValue'; // This works

constObj = { newKey: 'newValue' }; // TypeError: Assignment to constant variable.

Arrays Example:

const constArr = [1, 2, 3];
constArr.push(4); // This works

constArr = [4, 5, 6]; // TypeError: Assignment to constant variable.

Common Myths and Misconceptions

  1. Myth: const Makes Variables Immutable
    • Reality: const ensures that the variable identifier cannot be reassigned, but it does not make the value immutable. Objects and arrays declared with const can still be modified.
  2. Myth: let and const Are Not Hoisted
    • Reality: Both let and const are hoisted, but unlike var, they are not initialized until their declaration is evaluated. Accessing them before their declaration results in a ReferenceError due to the temporal dead zone.
  3. Myth: let Is Just a Better var
    • Reality: let is indeed an improvement over var for block-scoping, hoisting with a temporal dead zone, and preventing redeclaration. However, it should be used intentionally, considering its unique properties. Simply replacing all var with let in existing code may lead to unintended consequences.
  4. Myth: var Should Always Be Avoided
    • Reality: This is less of a Myth and more of a best practice, While var is generally less preferred due to its scoping and hoisting behavior, it can still be useful in certain legacy codebases or specific scenarios where function scope is desired.

Best Practices

  • Avoid using var in modern JavaScript due to its function-scoping and hoisting issues. It can be useful in legacy codebases, but for new code, prefer let or const.
  • Define variables with const by default. Use const for variables that should not be reassigned after their initial declaration. Ideal for constants, fixed values, or when working with objects and arrays that should not be reassigned. Note that const allows mutation of objects and arrays, so use it when the reference should remain constant.
  • Use let when you need a block-scoped variable that can be reassigned. Ideal for variables that need to be updated, such as counters in loops or values that will change over time.

Conclusion

Understanding the differences between var, let, and const is essential for writing efficient and bug-free JavaScript code. While they can be used similarly in many contexts, their differences in scope, hoisting, re-declaration, and re-assignment can significantly impact the behavior of your code. Using const by default and let when necessary is generally recommended for modern JavaScript to ensure better scoping and performance. Additionally, being aware of common myths and misconceptions will help you make more informed decisions when declaring variables.