📦 Variables & Scope

Storing and Managing Data

Variables & Scope

Variables are containers for storing data values. Understanding variable declarations and scope is fundamental to writing clean, bug-free JavaScript code.

📌 Variable Declarations

1. var (Old Way - Avoid)

// Function-scoped, can be redeclared
var name = 'John';
var name = 'Jane';  // No error, but problematic

// Hoisted to top of function
console.log(x);  // undefined (not an error!)
var x = 5;

// Function scope
function test() {
    var y = 10;
    if (true) {
        var y = 20;  // Same variable!
        console.log(y);  // 20
    }
    console.log(y);  // 20 (not 10!)
}

2. let (Modern - Block Scoped)

// Block-scoped, cannot be redeclared
let age = 25;
// let age = 30;  // Error: Cannot redeclare

// Can be reassigned
age = 26;  // OK

// Block scope
if (true) {
    let message = 'Hello';
    console.log(message);  // 'Hello'
}
// console.log(message);  // Error: message is not defined

// Loop scope
for (let i = 0; i < 3; i++) {
    console.log(i);  // 0, 1, 2
}
// console.log(i);  // Error: i is not defined

// Not hoisted (Temporal Dead Zone)
// console.log(name);  // Error: Cannot access before initialization
let name = 'John';

3. const (Modern - Constant)

// Block-scoped, cannot be reassigned
const PI = 3.14159;
// PI = 3.14;  // Error: Assignment to constant variable

// Must be initialized
// const x;  // Error: Missing initializer

// Block scope
const API_URL = 'https://api.example.com';

// Objects and arrays can be mutated
const person = { name: 'John' };
person.name = 'Jane';  // OK - mutating property
person.age = 30;       // OK - adding property
// person = {};        // Error - reassigning variable

const numbers = [1, 2, 3];
numbers.push(4);      // OK - mutating array
numbers[0] = 10;      // OK - changing element
// numbers = [];      // Error - reassigning variable

Best Practices

🎯 Scope

Global Scope

// Variables declared outside functions
const globalVar = 'I am global';

function test() {
    console.log(globalVar);  // Accessible everywhere
}

test();
console.log(globalVar);  // Also accessible here

// In browsers, global variables attach to window
var oldGlobal = 'attached to window';
console.log(window.oldGlobal);  // Works

// let and const don't attach to window
let newGlobal = 'not on window';
console.log(window.newGlobal);  // undefined

Function Scope

function myFunction() {
    const functionScoped = 'Only inside function';
    
    console.log(functionScoped);  // Works
    
    function innerFunction() {
        console.log(functionScoped);  // Can access parent scope
    }
    
    innerFunction();
}

myFunction();
// console.log(functionScoped);  // Error: Not accessible outside

// Each function has its own scope
function outer() {
    const x = 10;
    
    function inner() {
        const x = 20;  // Different variable
        console.log(x);  // 20
    }
    
    inner();
    console.log(x);  // 10
}

Block Scope

// let and const are block-scoped
{
    const blockVar = 'inside block';
    console.log(blockVar);  // Works
}
// console.log(blockVar);  // Error

// if statements
if (true) {
    let message = 'Hello';
    const value = 42;
    console.log(message, value);  // Works
}
// console.log(message);  // Error

// for loops
for (let i = 0; i < 3; i++) {
    const squared = i * i;
    console.log(squared);
}
// console.log(i);  // Error
// console.log(squared);  // Error

// switch statements
switch (true) {
    case true:
        let caseVar = 'case 1';
        console.log(caseVar);
        break;
}
// console.log(caseVar);  // Error

Lexical Scope (Closures)

// Inner functions access outer scope
function outer() {
    const outerVar = 'I am outer';
    
    function inner() {
        console.log(outerVar);  // Can access outer variable
    }
    
    return inner;
}

const myFunction = outer();
myFunction();  // 'I am outer' - closure in action!

// Practical closure example
function createCounter() {
    let count = 0;  // Private variable
    
    return {
        increment() {
            count++;
            return count;
        },
        decrement() {
            count--;
            return count;
        },
        getCount() {
            return count;
        }
    };
}

const counter = createCounter();
console.log(counter.increment());  // 1
console.log(counter.increment());  // 2
console.log(counter.decrement());  // 1
console.log(counter.getCount());   // 1
// console.log(count);  // Error: count is private

🏗️ Hoisting

Variable Hoisting

// var is hoisted
console.log(x);  // undefined (not an error)
var x = 5;

// Equivalent to:
var x;
console.log(x);  // undefined
x = 5;

// let and const are NOT hoisted (Temporal Dead Zone)
// console.log(y);  // Error: Cannot access before initialization
let y = 10;

// console.log(z);  // Error: Cannot access before initialization
const z = 15;

Function Hoisting

// Function declarations are hoisted
sayHello();  // Works! 'Hello'

function sayHello() {
    console.log('Hello');
}

// Function expressions are NOT hoisted
// greet();  // Error: greet is not a function
const greet = function() {
    console.log('Hi');
};

// Arrow functions are NOT hoisted
// welcome();  // Error: welcome is not a function
const welcome = () => {
    console.log('Welcome');
};

🎨 Naming Conventions

// camelCase for variables and functions (standard)
let userName = 'John';
let totalAmount = 100;
function calculateTotal() {}

// PascalCase for classes and constructors
class UserAccount {}
function Person() {}

// UPPER_SNAKE_CASE for constants
const MAX_SIZE = 100;
const API_KEY = 'abc123';
const DATABASE_URL = 'mongodb://localhost';

// Valid names
let name = 'John';
let _private = 'internal';
let $jquery = 'selector';
let name2 = 'test';

// Invalid names (syntax errors)
// let 2name = 'test';  // Cannot start with number
// let my-name = 'test';  // Hyphens not allowed
// let my name = 'test';  // Spaces not allowed
// let class = 'test';  // Reserved keyword

// Descriptive names (best practice)
// Good
let userAge = 25;
let isLoggedIn = true;
let totalPrice = 99.99;

// Bad
let x = 25;
let flag = true;
let temp = 99.99;

🔄 Variable Assignment Patterns

Multiple Declarations

// Separate declarations (recommended)
let firstName = 'John';
let lastName = 'Doe';
let age = 30;

// Single statement (valid but less readable)
let a = 1, b = 2, c = 3;

// Multiple const
const PI = 3.14159,
      E = 2.71828,
      PHI = 1.61803;

Destructuring Assignment

// Array destructuring
const colors = ['red', 'green', 'blue'];
const [first, second, third] = colors;
console.log(first);   // 'red'
console.log(second);  // 'green'

// Object destructuring
const user = {
    name: 'John',
    age: 30,
    city: 'New York'
};
const { name, age, city } = user;
console.log(name);  // 'John'
console.log(age);   // 30

// With different variable names
const { name: userName, age: userAge } = user;
console.log(userName);  // 'John'

// Default values
const { country = 'USA' } = user;
console.log(country);  // 'USA' (default)

Swap Variables

// Old way (using temp variable)
let a = 1;
let b = 2;
let temp = a;
a = b;
b = temp;
console.log(a, b);  // 2, 1

// Modern way (destructuring)
let x = 10;
let y = 20;
[x, y] = [y, x];
console.log(x, y);  // 20, 10

🛡️ Common Pitfalls

// 1. Forgetting to declare (creates global)
function test() {
    // x = 5;  // BAD: Creates global variable
    let x = 5;  // GOOD: Local variable
}

// 2. var in loops
for (var i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Prints: 3, 3, 3 (not 0, 1, 2!)

// Fix with let
for (let i = 0; i < 3; i++) {
    setTimeout(() => console.log(i), 100);
}
// Prints: 0, 1, 2

// 3. Const doesn't make objects immutable
const obj = { name: 'John' };
obj.name = 'Jane';  // Allowed!
// obj = {};  // Error

// To make immutable:
const frozen = Object.freeze({ name: 'John' });
// frozen.name = 'Jane';  // Silently fails (error in strict mode)

// 4. Temporal Dead Zone
{
    // console.log(myVar);  // Error: TDZ
    let myVar = 5;
}

// 5. Redeclaring with let
let value = 10;
// let value = 20;  // Error: Already declared

💡 Practical Examples

Counter with Closure

function createCounter(initialValue = 0) {
    let count = initialValue;
    
    return {
        increment(amount = 1) {
            count += amount;
            return count;
        },
        decrement(amount = 1) {
            count -= amount;
            return count;
        },
        reset() {
            count = initialValue;
            return count;
        },
        getValue() {
            return count;
        }
    };
}

const counter = createCounter(10);
console.log(counter.increment());    // 11
console.log(counter.increment(5));   // 16
console.log(counter.decrement(3));   // 13
console.log(counter.reset());        // 10

Configuration Object

// Using const for configuration
const config = {
    apiUrl: 'https://api.example.com',
    timeout: 5000,
    retries: 3,
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer token123'
    }
};

// Can modify properties
config.timeout = 10000;

// Object.freeze for immutable config
const immutableConfig = Object.freeze({
    version: '1.0.0',
    environment: 'production'
});

// immutableConfig.version = '2.0.0';  // Silently fails

Module Pattern

const calculator = (function() {
    // Private variables
    let result = 0;
    
    // Private function
    function log(operation, value) {
        console.log(`${operation}: ${value}`);
    }
    
    // Public API
    return {
        add(num) {
            result += num;
            log('Added', num);
            return this;
        },
        subtract(num) {
            result -= num;
            log('Subtracted', num);
            return this;
        },
        multiply(num) {
            result *= num;
            log('Multiplied', num);
            return this;
        },
        getResult() {
            return result;
        },
        reset() {
            result = 0;
            return this;
        }
    };
})();

// Usage
calculator.add(10).multiply(2).subtract(5);
console.log(calculator.getResult());  // 15

🎯 Key Takeaways