π Today's Learning Goals
- Understand JavaScript scope concepts
- Master variable hoisting mechanism
- Learn the differences between let, const, and var
- Understand the basics of closures
π Scope
Scope determines the accessibility of variables and functions.
Global Scope
// Global variables
var globalVar = "I am a global variable";
let globalLet = "I am also a global variable";
const globalConst = "I am still a global variable";
function testGlobalScope() {
console.log(globalVar); // "I am a global variable"
console.log(globalLet); // "I am also a global variable"
console.log(globalConst); // "I am still a global variable"
}
testGlobalScope();
console.log(globalVar); // "I am a global variable" (accessible outside function)
Local Scope
Function Scope
function testFunctionScope() {
var localVar = "I am a local variable";
let localLet = "I am also a local variable";
const localConst = "I am still a local variable";
console.log(localVar); // "I am a local variable"
console.log(localLet); // "I am also a local variable"
console.log(localConst); // "I am still a local variable"
}
testFunctionScope();
// console.log(localVar); // ReferenceError: localVar is not defined
// console.log(localLet); // ReferenceError: localLet is not defined
// console.log(localConst); // ReferenceError: localConst is not defined
Block Scope
// var has no block scope
if (true) {
var blockVar = "var variable";
}
console.log(blockVar); // "var variable" (accessible)
// let and const have block scope
if (true) {
let blockLet = "let variable";
const blockConst = "const variable";
}
// console.log(blockLet); // ReferenceError: blockLet is not defined
// console.log(blockConst); // ReferenceError: blockConst is not defined
// Block scope in loops
for (let i = 0; i < 3; i++) {
// i is only valid within the loop block
}
// console.log(i); // ReferenceError: i is not defined
for (var j = 0; j < 3; j++) {
// j is accessible outside the loop
}
console.log(j); // 3
β¬οΈ Variable Hoisting
Variable hoisting is a JavaScript feature where variable and function declarations are "hoisted" to the top of their scope.
var Hoisting
// Before code execution, the JavaScript engine processes it like this:
console.log(hoistedVar); // undefined (no error)
var hoistedVar = "I was hoisted";
// Equivalent to:
var hoistedVar; // Declaration is hoisted to the top
console.log(hoistedVar); // undefined
hoistedVar = "I was hoisted"; // Assignment stays in place
Temporal Dead Zone for let and const
// let and const are not hoisted, they have a temporal dead zone
console.log(hoistedLet); // ReferenceError: Cannot access 'hoistedLet' before initialization
let hoistedLet = "I am not hoisted";
console.log(hoistedConst); // ReferenceError: Cannot access 'hoistedConst' before initialization
const hoistedConst = "I am also not hoisted";
Function Hoisting
// Function declarations are fully hoisted
console.log(hoistedFunction()); // "I was fully hoisted"
function hoistedFunction() {
return "I was fully hoisted";
}
// Function expressions are not hoisted
console.log(notHoistedFunction()); // TypeError: notHoistedFunction is not a function
var notHoistedFunction = function () {
return "I was not hoisted";
};
π var vs let vs const
Scope Comparison
// var - function scope
function testVar() {
if (true) {
var varVariable = "var variable";
}
console.log(varVariable); // "var variable" (accessible)
}
// let - block scope
function testLet() {
if (true) {
let letVariable = "let variable";
}
// console.log(letVariable); // ReferenceError: letVariable is not defined
}
// const - block scope
function testConst() {
if (true) {
const constVariable = "const variable";
}
// console.log(constVariable); // ReferenceError: constVariable is not defined
}
Duplicate Declaration Comparison
// var allows duplicate declarations
var duplicateVar = "First time";
var duplicateVar = "Second time"; // No error
console.log(duplicateVar); // "Second time"
// let does not allow duplicate declarations
let duplicateLet = "First time";
// let duplicateLet = "Second time"; // SyntaxError: Identifier 'duplicateLet' has already been declared
// const does not allow duplicate declarations
const duplicateConst = "First time";
// const duplicateConst = "Second time"; // SyntaxError: Identifier 'duplicateConst' has already been declared
Reassignment Comparison
// var can be reassigned
var reassignableVar = "Original value";
reassignableVar = "New value";
console.log(reassignableVar); // "New value"
// let can be reassigned
let reassignableLet = "Original value";
reassignableLet = "New value";
console.log(reassignableLet); // "New value"
// const cannot be reassigned
const reassignableConst = "Original value";
// reassignableConst = "New value"; // TypeError: Assignment to constant variable
Real-world Application Example
// Classic problem: var in loops
console.log("=== var problem in loops ===");
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log("var i:", i); // Output: 3, 3, 3
}, 100);
}
// Solution 1: Use let
console.log("=== let solution ===");
for (let j = 0; j < 3; j++) {
setTimeout(() => {
console.log("let j:", j); // Output: 0, 1, 2
}, 200);
}
// Solution 2: Use closure
console.log("=== closure solution ===");
for (var k = 0; k < 3; k++) {
(function (index) {
setTimeout(() => {
console.log("closure k:", index); // Output: 0, 1, 2
}, 300);
})(k);
}
π Closure Basics
Closures refer to a function's ability to access variables from its outer scope.
Basic Closure Example
function outerFunction(x) {
// Outer function variable
let outerVariable = x;
// Inner function
function innerFunction(y) {
// Inner function can access outer function variables
return outerVariable + y;
}
return innerFunction;
}
// Create closure
let closure = outerFunction(10);
console.log(closure(5)); // 15
// Another closure
let anotherClosure = outerFunction(20);
console.log(anotherClosure(5)); // 25
Real-world Closure Applications
// 1. Data privacy
function createCounter() {
let count = 0; // Private variable
return {
increment: function () {
count++;
return count;
},
decrement: function () {
count--;
return count;
},
getCount: function () {
return count;
},
};
}
let counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
// console.log(counter.count); // undefined (cannot directly access private variable)
// 2. Function factory
function createMultiplier(factor) {
return function (number) {
return number * factor;
};
}
let double = createMultiplier(2);
let triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
Closure Considerations
// Closures can cause memory leaks
function createFunctions() {
let functions = [];
for (var i = 0; i < 3; i++) {
functions.push(function () {
return i; // All functions reference the same i
});
}
return functions;
}
let funcs = createFunctions();
funcs.forEach((func) => {
console.log(func()); // Output: 3, 3, 3
});
// Correct closure usage
function createCorrectFunctions() {
let functions = [];
for (let i = 0; i < 3; i++) {
functions.push(function () {
return i; // Each function has its own i
});
}
return functions;
}
let correctFuncs = createCorrectFunctions();
correctFuncs.forEach((func) => {
console.log(func()); // Output: 0, 1, 2
});
π― Practice Exercises
Exercise 1: Scope Testing
function scopeTest() {
console.log("=== Scope Test ===");
// Global variables
var globalVar = "Global var";
let globalLet = "Global let";
const globalConst = "Global const";
function innerFunction() {
// Local variables
var localVar = "Local var";
let localLet = "Local let";
const localConst = "Local const";
console.log("Inner function can access:");
console.log("Global var:", globalVar);
console.log("Global let:", globalLet);
console.log("Global const:", globalConst);
console.log("Local var:", localVar);
console.log("Local let:", localLet);
console.log("Local const:", localConst);
}
innerFunction();
console.log("Outer function can access:");
console.log("Global var:", globalVar);
console.log("Global let:", globalLet);
console.log("Global const:", globalConst);
// console.log("Local var:", localVar); // ReferenceError
}
scopeTest();
Exercise 2: Hoisting Test
function hoistingTest() {
console.log("=== Hoisting Test ===");
// var hoisting
console.log("var variable:", hoistedVar); // undefined
var hoistedVar = "var value";
// Function hoisting
console.log("Function call:", hoistedFunc()); // "Function was hoisted"
function hoistedFunc() {
return "Function was hoisted";
}
// let temporal dead zone
try {
console.log("let variable:", hoistedLet);
} catch (error) {
console.log("let error:", error.message);
}
let hoistedLet = "let value";
// const temporal dead zone
try {
console.log("const variable:", hoistedConst);
} catch (error) {
console.log("const error:", error.message);
}
const hoistedConst = "const value";
}
hoistingTest();
Exercise 3: Closure Application - Cached Function
function createCachedFunction(fn) {
let cache = {}; // Private cache
return function (...args) {
let key = JSON.stringify(args);
if (cache[key]) {
console.log("Getting result from cache");
return cache[key];
}
console.log("Computing new result");
let result = fn(...args);
cache[key] = result;
return result;
};
}
// Create cached version of fibonacci function
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
let cachedFibonacci = createCachedFunction(fibonacci);
// Test caching functionality
console.log("=== Cached Function Test ===");
console.log("fibonacci(10):", cachedFibonacci(10));
console.log("fibonacci(10):", cachedFibonacci(10)); // Get from cache
console.log("fibonacci(5):", cachedFibonacci(5));
console.log("fibonacci(5):", cachedFibonacci(5)); // Get from cache
π Today's Key Points Summary
- Scope: Global scope, function scope, block scope
- Variable Hoisting: var is hoisted, let/const have temporal dead zone
- Variable Declarations: Differences and usage scenarios for var, let, const
- Closure Basics: Function's ability to access outer scope variables
- Best Practices: Recommend using let/const, avoid var problems
π Tomorrow's Preview
Tomorrow we'll learn about object basics, including:
- Object creation and access
- Object methods and properties
- Object iteration and manipulation
- Object literal syntax
π‘ Learning Tips
- Understand scope: Master the characteristics of different scopes
- Avoid hoisting pitfalls: Use let/const instead of var
- Master closures: Understand closure concepts and applications
- Practice: Understand these concepts through actual code
Congratulations on completing Day 7! π
You've mastered scope and variable hoisting. Tomorrow we'll learn about JavaScript's core data structure - objects!
Top comments (0)