Variables, Scope, Hoisting, and Temporal Dead Zones
Build a precise understanding of var, let, const, lexical environments, scope chains, hoisting, and why declarations behave differently.
var, let, and const
var is function-scoped, while let and const are block-scoped. const prevents reassignment of the binding, but it does not make referenced objects immutable. This distinction between binding immutability and object immutability is essential.
Modern JavaScript generally favors const by default and let when reassignment is actually required.
const user = { name: 'Suriya' };
user.name = 'Alex';
console.log(user.name);
// user = {}; // TypeErrorvaris function-scoped.letandconstare block-scoped.constprotects a binding, not the contents of an object.
What does `const` guarantee?
Lexical Scope and the Scope Chain
JavaScript uses lexical scoping: where a function is written determines which outer variables it can access. When an identifier is referenced, JavaScript searches the current lexical environment and then walks outward through enclosing environments until it finds the binding or reaches the global environment.
This lexical relationship is the foundation for closures.
- Scope is determined by lexical structure.
- Identifier lookup proceeds through enclosing environments.
- Closures depend on lexical environments remaining accessible.
What primarily determines which outer variables a function can access?
Hoisting Is Not Moving Code
Hoisting is a useful informal term for the fact that declarations are processed before execution of their surrounding code. It does not mean JavaScript literally moves source lines to the top.
Function declarations can generally be called before their declaration. var declarations are initialized with undefined, while let and const bindings exist but cannot be accessed before initialization because of the Temporal Dead Zone.
sayHello();
function sayHello() {
console.log('Hello');
}
console.log(value);
var value = 10;
// console.log(count); // ReferenceError
let count = 10;- Hoisting is about declaration instantiation, not textual movement.
varcan be observed as undefined before assignment.letandconsthave a Temporal Dead Zone before initialization.
What happens when code accesses a `let` variable before its declaration is initialized?
Temporal Dead Zone
The Temporal Dead Zone (TDZ) is the period between entering a scope where a lexical binding exists and reaching the declaration's initialization. During that period, reading or accessing the binding results in a ReferenceError.
The TDZ is a runtime concept, not merely a parser restriction. This explains why typeof someLetVariable can throw when the variable is in the TDZ.
{
// console.log(typeof name); // ReferenceError
let name = 'Suriya';
console.log(typeof name);
}- TDZ applies to let, const, and class declarations.
- A lexical binding can exist without being initialized.
- TDZ helps prevent accidental use of variables before initialization.
Which declaration is subject to the Temporal Dead Zone?