Variables (let, const, var)
1. Welcome and Icebreaker:
- Welcome! What’s the trickiest bug you’ve encountered that was related to variable scope or reassignment?
2. Outline the Session:
- Today, we’ll explore variable declarations in JavaScript and TypeScript:
let,const, andvar. - We will focus on their scope, hoisting (for
var), and reassignment/re-declaration differences. - Learning Outcomes: Understand how to choose the appropriate variable declaration keyword for different scenarios.
- Feel free to jump in with questions.
3. Concept Explanation:
-
In JavaScript (and thus TypeScript), variables are used to store data values. How you declare a variable affects its behavior, particularly its scope and whether it can be reassigned or re-declared.
-
var(The Old Way - Avoid in Modern JavaScript/TypeScript):- Scope: Function-scoped or globally-scoped. If declared outside any function, it’s global. If inside a function, it’s accessible anywhere within that function.
- Hoisting:
vardeclarations are hoisted to the top of their scope (function or global) and initialized withundefinedbefore the code is executed. This means you can use a variable before its textual declaration in the code, though its value will beundefineduntil the assignment. - Re-declaration: Can be re-declared within the same scope without error.
- Reassignment: Can be reassigned.
-
let(The Modern Way - Preferred for Variables That Change):- Scope: Block-scoped (
{}). A variable declared withletis only accessible within the block of code (e.g., inside anifstatement,forloop, or a standalone block) where it is defined. - Hoisting:
letdeclarations are hoisted, but not initialized. Accessing them before the declaration results in aReferenceError(this is often called the “Temporal Dead Zone”). - Re-declaration: Cannot be re-declared within the same scope.
- Reassignment: Can be reassigned.
- Scope: Block-scoped (
-
const(The Modern Way - Preferred for Variables That Don’t Change):- Scope: Block-scoped (
{}), just likelet. - Hoisting: Similar to
let,constdeclarations are hoisted but not initialized, leading to a Temporal Dead Zone. - Re-declaration: Cannot be re-declared within the same scope.
- Reassignment: Cannot be reassigned after initialization. It must be initialized at the time of declaration.
- Important Note for Objects/Arrays: For
constvariables holding objects or arrays, the variable itself cannot be reassigned to a new object or array. However, the properties of the object or the elements of the array can be modified.
- Important Note for Objects/Arrays: For
- Scope: Block-scoped (
-
TypeScript and Variables: TypeScript uses these same JavaScript rules but adds type annotations. The choice between
let,const, andvaris primarily about scope and mutability, not types. -
Recommendation: Prefer
constby default. Useletonly when you know a variable’s value needs to change. Avoidvarin modern codebases to prevent common bugs related to its scoping and hoisting behavior.
4. Live Coding Demonstration:
console.log("--- var examples ---");
function varScopeTest() {
if (true) {
var x = 10;
console.log("Inside if (var x):", x); // 10
}
console.log("Outside if, inside function (var x):", x); // 10 (function-scoped)
// Hoisting with var
console.log("y before declaration (var y):", y); // undefined
var y = 20;
console.log("y after declaration (var y):", y); // 20
var z = 30;
var z = 40; // Re-declaration allowed
console.log("z after re-declaration (var z):", z); // 40
z = 50; // Reassignment allowed
console.log("z after reassignment (var z):", z); // 50
}
varScopeTest();
// console.log(x); // Error: x is not defined (outside function scope)
console.log("\n--- let examples ---");
function letScopeTest() {
if (true) {
let a: number = 100;
console.log("Inside if (let a):", a); // 100
// let a: number = 150; // Error: Cannot redeclare block-scoped variable 'a'.
}
// console.log("Outside if, inside function (let a):", a); // Error: Cannot find name 'a'. (block-scoped)
// Temporal Dead Zone with let
// console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b: number = 200;
console.log("b after declaration (let b):", b); // 200
let c: string = "hello";
// let c: string = "world"; // Error: Cannot redeclare block-scoped variable 'c'.
c = "world"; // Reassignment allowed
console.log("c after reassignment (let c):", c); // world
}
letScopeTest();
console.log("\n--- const examples ---");
function constScopeTest() {
const PI: number = 3.14159;
console.log("PI (const):", PI);
// PI = 3.14; // Error: Cannot assign to 'PI' because it is a constant.
// const PI: number = 3.14; // Error: Cannot redeclare block-scoped variable 'PI'.
if (true) {
const G: number = 9.8;
console.log("Inside if (const G):", G);
}
// console.log("Outside if (const G):", G); // Error: Cannot find name 'G'. (block-scoped)
// Const with objects and arrays
const person: { name: string; age: number } = {
name: "Alice",
age: 30
};
console.log("Person (const object):", person);
// We can modify properties of a const object
person.name = "Bob";
person.age = 31;
console.log("Modified Person (const object):", person);
// But we cannot reassign the const variable itself
// person = { name: "Charlie", age: 32 }; // Error: Cannot assign to 'person' because it is a constant.
const numbers: number[] = [1, 2, 3];
console.log("Numbers (const array):", numbers);
// We can modify the array (e.g., push new elements, change elements)
numbers.push(4);
numbers[0] = 0;
console.log("Modified Numbers (const array):", numbers);
// But we cannot reassign the const variable to a new array
// numbers = [5, 6, 7]; // Error: Cannot assign to 'numbers' because it is a constant.
}
constScopeTest();
// Global scope example
let globalLet = "I am global let";
const globalConst = "I am global const";
var globalVar = "I am global var";
{
let blockLet = "I am block let";
const blockConst = "I am block const";
var blockVar = "I am block var (but actually function/global scoped)";
console.log(blockLet);
console.log(blockConst);
}
// console.log(blockLet); // Error
// console.log(blockConst); // Error
console.log(blockVar); // "I am block var..." - accessible if this code is not in a function
// If this whole script is treated as a module, `var` might behave differently
// than traditional script-tag global `var`.
5. Tasks:
- Short Exercise:
- Declare a variable
countusingletand initialize it to0. Increment it and print its value. - Declare a variable
appNameusingconstand initialize it to your favorite application’s name. Try to reassign it and observe the error. - Create an object
userDetailsusingconstwith propertiesid(number) andusername(string). Modify theusernameand print the object. Try to reassignuserDetailsto a new object and observe the error. - Write a
forloop that usesletto declare its counter. Inside the loop, print the counter. After the loop, try to print the counter again and observe if it’s accessible. - (Challenge) Write a function that demonstrates the difference in scope between
varandletwithin anifblock inside that function.
- Declare a variable