5  Variable Declarations

In JavaScript, the keywords let, const, and var are all used to declare variables, but they have important differences in terms of scope, hoisting, reassignment capabilities, and when they were introduced to the language. Let me walk you through each one and explain when to use them.

5.1 When to Use Each Declaration

Here’s a practical guide for when to use each type of declaration:

5.1.1 Use const by default:

  • It makes your intentions clear - this value shouldn’t change
  • Helps prevent bugs from accidental reassignment
  • Use for all variables that won’t be reassigned

5.1.2 Use let when you need to reassign:

  • Loop counters (for (let i = 0; i < 10; i++))
  • Variables that change value throughout your code
  • When you’re accumulating a value

5.1.3 Avoid var in modern code:

  • It’s considered outdated in modern JavaScript
  • The lack of block scoping can lead to unexpected bugs
  • Less predictable behavior due to hoisting

5.2 var: The Original Variable Declaration

var was the original way to declare variables in JavaScript before ES6 (ECMAScript 2015).

var name = "John";
var age = 30;

5.2.1 Key Characteristics of var:

  1. Function-scoped: Variables declared with var are scoped to the function in which they are declared, or globally if declared outside any function.
function exampleFunction() {
  var insideVar = "I'm inside the function";
  console.log(insideVar); // Works fine
}
// console.log(insideVar); // Would throw ReferenceError
  1. Hoisting: Variables declared with var are “hoisted” to the top of their scope, which means you can use them before their declaration in the code.
console.log(hoistedVar); // Outputs: undefined (not an error!)
var hoistedVar = "I'm hoisted";

What actually happens behind the scenes is:

var hoistedVar; // Declaration is hoisted
console.log(hoistedVar); // undefined
hoistedVar = "I'm hoisted"; // Assignment stays in place
  1. No block scope: var doesn’t respect block scope (like in if statements or loops):
if (true) {
  var blockVar = "I'm in a block";
}
console.log(blockVar); // Outputs: "I'm in a block" (leaks outside the block!)
  1. Can be redeclared: You can declare the same variable multiple times without errors:
var example = "first";
var example = "second"; // No error, just overwrites

5.3 let: Block-Scoped Variable Declaration

let was introduced in ES6 (2015) to address issues with var.

let name = "John";
let age = 30;

5.3.1 Key Characteristics of let:

  1. Block-scoped: Variables declared with let are scoped to the nearest curly braces {} (block).
if (true) {
  let blockLet = "I'm in a block";
  console.log(blockLet); // Works fine
}
// console.log(blockLet); // ReferenceError: blockLet is not defined
  1. Hoisting with temporal dead zone: let variables are hoisted but not initialized, creating what’s called a “temporal dead zone” where accessing the variable before declaration throws an error.
// console.log(hoistedLet); // ReferenceError: Cannot access 'hoistedLet' before initialization
let hoistedLet = "I'm hoisted differently";
  1. Cannot be redeclared: You cannot declare the same variable multiple times in the same scope:
let example = "first";
// let example = "second"; // SyntaxError: Identifier 'example' has already been declared
  1. Can be reassigned: You can change the value after declaration:
let count = 1;
count = 2; // This is allowed

5.4 const: Constant Variable Declaration

const was also introduced in ES6 alongside let.

const PI = 3.14159;
const MAX_USERS = 100;

5.4.1 Key Characteristics of const:

  1. Block-scoped: Just like let, const variables are block-scoped.
if (true) {
  const blockConst = "I'm in a block";
  console.log(blockConst); // Works fine
}
// console.log(blockConst); // ReferenceError: blockConst is not defined
  1. Hoisting with temporal dead zone: Similar to let, const variables are hoisted but not initialized until their declaration is reached.

  2. Cannot be redeclared: Like let, you cannot redeclare a const variable in the same scope.

  3. Cannot be reassigned: This is the key difference between const and let - once assigned, a const variable cannot be given a new value:

const PI = 3.14;
// PI = 3.14159; // TypeError: Assignment to constant variable

However, for objects and arrays (which are reference types), the contents can still be modified:

const person = { name: "John" };
person.name = "Jane"; // This works! The object's content can change
// person = { name: "Jane" }; // This would fail - cannot reassign the reference

const numbers = [1, 2, 3];
numbers.push(4); // This works! The array's content can change
// numbers = [1, 2, 3, 4]; // This would fail - cannot reassign the reference

5.5 Practical Example Putting It All Together

Here’s a practical example showing all three in action:

function calculateTotalPrice(items, taxRate) {
  // Using const for values that won't change
  const TAX_MULTIPLIER = 1 + taxRate;
  
  // Using let for a counter that will be updated
  let subtotal = 0;
  
  // In older code, you might see var
  var discountApplied = false;
  
  // A loop using let for the counter
  for (let i = 0; i < items.length; i++) {
    const item = items[i]; // Each iteration gets a new constant
    
    subtotal += item.price;
    
    if (item.discounted) {
      discountApplied = true;
    }
  }
  
  // Block scope demonstration
  if (discountApplied) {
    const message = "Discount applied!";
    console.log(message); // Works
    
    // let scoped message
    let detail = "Some items were on sale";
    console.log(detail); // Works
  }
  // console.log(message); // Would throw ReferenceError - const is block-scoped
  // console.log(detail); // Would throw ReferenceError - let is block-scoped
  console.log(discountApplied); // Works - var is function-scoped
  
  // Calculate and return the final price
  const totalPrice = subtotal * TAX_MULTIPLIER;
  return totalPrice;
}

5.6 How This Relates to Your Experience

Since you’re coming from R and Python:

  • const is similar to constants in other languages or final variables
  • let is closest to most variable declarations in Python
  • R doesn’t have block scope the same way JavaScript does, so this might be a new concept
  • Python’s scoping rules are cleaner than var but not quite as strict as let/const

Modern JavaScript best practices strongly favor const and let over var. As a beginner focused on learning modern JavaScript, you’ll want to make the same habit.

Does this explanation help clarify the differences? Is there any specific aspect of variable declarations you’d like me to go into more detail on?