OSJavaScript.003: Variables and Constants — let, const, var, Reassignment, Scope, and the Temporal Dead Zone

Anime-style editorial artwork of a developer studying JavaScript scope and variable concepts on dark monitors with neon-green accents.

Elementary Overview

JavaScript gives you three main declaration keywords: let, const, and var. They all create bindings between names and values, but they do not behave the same way. Modern JavaScript normally favors const for bindings that will not be reassigned and let for bindings that must change. var still matters because older codebases use it and because its function-scoped behavior helps explain several classic JavaScript bugs.

This lesson follows OSJavaScript.002: Values and Primitive Types. That lesson explained what kinds of values JavaScript stores. OSJavaScript.003 focuses on how names are created, reassigned, scoped, and initialized.

Traversy Media introduces let and const declarations and shows why modern JavaScript added them alongside var.

Learning Objectives

  • Declare bindings with let, const, and var.
  • Explain the difference between declaration, initialization, assignment, and reassignment.
  • Explain why const prevents rebinding but does not automatically freeze objects.
  • Distinguish block scope from function scope.
  • Recognize the Temporal Dead Zone for let and const.
  • Explain why reading a var binding before its declaration often produces undefined.
  • Choose a sensible declaration keyword in new code.

Declaration, Initialization, Assignment, and Reassignment

A declaration introduces a binding name into a scope. Initialization gives that binding its first value. Assignment stores a value in a binding, and reassignment changes the value later.

let temperature;      // declaration

temperature = 72;    // assignment after declaration

temperature = 75;    // reassignment

const siteName = "Mesa"; // declaration + required initialization

let can be declared without an initializer, in which case the binding receives undefined when execution reaches the declaration. A const declaration must include an initializer because the binding cannot later be reassigned.

let: Block-Scoped and Reassignable

let creates a block-scoped binding. A block is commonly delimited by braces in structures such as if, for, while, switch, and ordinary nested blocks. MDN’s let reference documents that let is scoped to its nearest enclosing block, function body, module, or global script scope.

let count = 1;

if (true) {
  let count = 2;
  console.log(count); // 2
}

console.log(count);   // 1

The inner count is a different binding from the outer count. This is called shadowing. The braces create a separate block scope, so changing the inner binding does not change the outer one.

const: A Binding That Cannot Be Reassigned

const also uses block scope, but its binding cannot be reassigned after initialization. This makes const useful when a name should continue to refer to the same value or object for the lifetime of that scope.

const voltage = 480;

voltage = 208; // TypeError: assignment to a constant variable

A critical beginner point is that const does not make an object immutable. It prevents the variable from being rebound to a different object. The object itself can still be changed unless other techniques such as Object.freeze() are used.

const miner = {
  model: "S21",
  online: true
};

miner.online = false; // allowed

// miner = {};        // not allowed
Web Dev Simplified compares var, let, and const, including reassignment and the practical reasons to choose one declaration form over another.

var: Function-Scoped Legacy Behavior

var predates let and const. Its most important beginner-level difference is scope: var is function-scoped rather than block-scoped. An if block or for loop does not create a new var scope by itself.

function demo() {
  if (true) {
    var status = "online";
  }

  console.log(status); // "online"
}

The same pattern with let would fail outside the if block because the binding would be block-scoped. This difference is one reason modern JavaScript style generally avoids introducing new var declarations.

Scope: Global, Function, and Block

Scope answers a simple question: where can this name be used? A global binding is visible broadly within the script or module environment. A function-scoped binding is available inside its function. A block-scoped binding is limited to the nearest enclosing block.

Dave Gray demonstrates global, function, local, and block scope while comparing var, let, and const.
const company = "HashWorks";

function report() {
  var region = "West";

  if (true) {
    let rack = 12;
    const targetTemp = 25;
    console.log(company, region, rack, targetTemp);
  }

  // rack and targetTemp are not available here
}

The Temporal Dead Zone

The Temporal Dead Zone, usually shortened to TDZ, is the period from the start of a block until execution reaches a let or const declaration. During that period, the binding exists conceptually but cannot be accessed. Attempting to read it throws a ReferenceError.

{
  console.log(power); // ReferenceError
  let power = 3500;
}

MDN explains that let and const remain inaccessible until control reaches their declaration and initialization. The word temporal matters because the restriction depends on execution order, not simply whether the declaration appears somewhere in the block.

Why var Looks Different Before Its Declaration

A var binding is created and initialized to undefined when its function or global execution context is established. That means code can often read it before the declaration line without receiving a TDZ error.

console.log(site); // undefined
var site = "Tacoma";

console.log(zone); // ReferenceError
let zone = "A";

This behavior is often described as hoisting. The safest beginner mental model is not that JavaScript literally moves source-code lines. Instead, the engine establishes declarations during environment setup, and the initialization rules differ by declaration type.

Redeclaration Rules

var allows the same name to be declared again in the same function scope. let and const do not allow another lexical declaration with the same name in the same scope. This stricter behavior catches accidental duplicate declarations earlier.

var mode = "auto";
var mode = "manual"; // allowed

let speed = 10;
// let speed = 20;    // SyntaxError

A Practical Rule for New Code

  • Use const by default when the binding will not be reassigned.
  • Use let when reassignment is part of the program’s logic.
  • Understand var so you can read older code and recognize function-scope and initialization behavior.
  • Do not assume const means immutable object.
  • Declare names before use so TDZ behavior is predictable and code remains easy to read.

Mini Lab

  1. Open the browser console introduced in OSJavaScript.001.
  2. Create a const binding named siteName.
  3. Create a let binding named activeMiners, then reassign it.
  4. Create an if block containing a new let binding and confirm that the name is unavailable outside the block.
  5. Repeat the experiment with var and observe the difference.
  6. Try reading a let binding before its declaration and observe the ReferenceError.
  7. Try reading a var binding before its declaration and observe undefined.
  8. Create a const object, change one property, then try to reassign the entire binding.

Knowledge Check

  1. Which declaration keyword is normally the best default when no reassignment is needed?
  2. Which modern keyword allows reassignment?
  3. Is var block-scoped?
  4. What does the Temporal Dead Zone describe?
  5. What happens if code reads a let binding inside its TDZ?
  6. What value is a var binding initialized with before its declaration line executes?
  7. Does const automatically freeze an object?
  8. Can let be redeclared with the same name in the same scope?

Answers

  1. const.
  2. let.
  3. No. var is function-scoped or global/script-scoped.
  4. The period from entering the relevant scope until a let or const declaration has been reached and initialized.
  5. A ReferenceError is thrown.
  6. undefined.
  7. No. The binding cannot be reassigned, but the referenced object can still be mutated.
  8. No, not in the same scope.

Primary References

Elementary Conclusion

JavaScript variables are not all declared the same way. const creates a non-reassignable block-scoped binding, let creates a reassignable block-scoped binding, and var creates a function-scoped binding with older initialization behavior. Scope determines where names are visible, while the Temporal Dead Zone explains why let and const cannot be read before initialization. These rules are foundational for conditions, loops, functions, closures, modules, and larger JavaScript programs.

BitcoinVersus.Tech Editor’s Note:
We volunteer daily to ensure the credibility of the information on this platform is Verifiably True. If you would like to support to help further secure the integrity of our research initiatives, please donate using the QR code provided

Bitcoin donation QR code for 5,000 sats.

For best QR-code scanning results, please scan this donation code from a desktop or larger screen. Mobile screens may prevent camera recognition.

Leave a Reply