javascript

examples

examples.js
/**
 * ============================================
 * 2.1 Variables - Examples
 * ============================================
 *
 * Comprehensive examples of var, let, and const
 */

// ============================================
// BASIC VARIABLE DECLARATION
// ============================================

console.log('=== BASIC VARIABLE DECLARATION ===\n');

// Declaration only
let firstName;
console.log('Declared but not initialized:', firstName); // undefined

// Declaration with initialization
let lastName = 'Doe';
console.log('Declared and initialized:', lastName); // "Doe"

// Assignment (changing value)
lastName = 'Smith';
console.log('After reassignment:', lastName); // "Smith"

// ============================================
// VAR - THE ORIGINAL WAY
// ============================================

console.log('\n=== VAR CHARACTERISTICS ===\n');

// 1. var is function scoped
function varFunctionScope() {
  if (true) {
    var insideIf = "I'm function scoped";
  }
  console.log('var inside if, accessed outside:', insideIf);
}
varFunctionScope();

// 2. var is hoisted
console.log('\nvar hoisting:');
console.log('Before declaration:', hoistedVar); // undefined, not error!
var hoistedVar = 'Now I have a value';
console.log('After declaration:', hoistedVar);

// 3. var can be redeclared
var color = 'red';
var color = 'blue'; // No error
console.log('\nvar redeclaration:', color); // "blue"

// 4. var creates global property (in browser)
var globalVar = "I'm on window object";
// console.log(window.globalVar); // Works in browser

// ============================================
// LET - THE MODERN WAY
// ============================================

console.log('\n=== LET CHARACTERISTICS ===\n');

// 1. let is block scoped
function letBlockScope() {
  if (true) {
    let insideIf = "I'm block scoped";
    console.log('let inside if:', insideIf);
  }
  // console.log(insideIf); // ReferenceError!
}
letBlockScope();
console.log('let respects block scope!');

// 2. let has Temporal Dead Zone
console.log('\nlet TDZ:');
// console.log(tdzVar); // Would throw: Cannot access 'tdzVar' before initialization
let tdzVar = 'I exist now';
console.log('After declaration:', tdzVar);

// 3. let cannot be redeclared in same scope
let uniqueVar = 'first';
// let uniqueVar = "second"; // SyntaxError!
console.log('\nlet prevents redeclaration in same scope');

// But different scopes are OK
let outerLet = 'outer';
if (true) {
  let outerLet = 'inner'; // Different scope, OK
  console.log('Inner scope let:', outerLet);
}
console.log('Outer scope let:', outerLet);

// ============================================
// CONST - CONSTANTS
// ============================================

console.log('\n=== CONST CHARACTERISTICS ===\n');

// 1. const must be initialized
const PI = 3.14159;
console.log('PI:', PI);
// const uninitialized; // SyntaxError: Missing initializer

// 2. const cannot be reassigned
const MAX_SIZE = 100;
// MAX_SIZE = 200; // TypeError: Assignment to constant variable
console.log('MAX_SIZE:', MAX_SIZE);

// 3. const is block scoped (like let)
if (true) {
  const blockConst = "I'm block scoped";
  console.log('const inside block:', blockConst);
}
// console.log(blockConst); // ReferenceError!

// 4. IMPORTANT: const allows mutation of objects/arrays!
console.log('\nconst with objects (mutation allowed):');
const person = { name: 'John', age: 30 };
console.log('Before mutation:', person);
person.age = 31; // OK - mutating property
person.city = 'NYC'; // OK - adding property
console.log('After mutation:', person);
// person = {}; // TypeError - cannot reassign reference

console.log('\nconst with arrays (mutation allowed):');
const numbers = [1, 2, 3];
console.log('Before mutation:', numbers);
numbers.push(4); // OK
numbers[0] = 100; // OK
console.log('After mutation:', numbers);
// numbers = []; // TypeError - cannot reassign reference

// ============================================
// SCOPE COMPARISON
// ============================================

console.log('\n=== SCOPE COMPARISON ===\n');

function scopeTest() {
  console.log('Inside function scope test:');

  if (true) {
    var varInBlock = 'var';
    let letInBlock = 'let';
    const constInBlock = 'const';

    console.log('  Inside if block:');
    console.log('    var:', varInBlock);
    console.log('    let:', letInBlock);
    console.log('    const:', constInBlock);
  }

  console.log('  Outside if block:');
  console.log('    var:', varInBlock); // Accessible!
  // console.log("    let:", letInBlock);  // ReferenceError
  // console.log("    const:", constInBlock); // ReferenceError
}
scopeTest();

// ============================================
// LOOP SCOPE - THE CLASSIC PROBLEM
// ============================================

console.log('\n=== LOOP SCOPE PROBLEM ===\n');

// The var problem in loops
console.log('Using var in setTimeout loop:');
for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log('  var i:', i); // All print 3!
  }, 10);
}

// The let solution
console.log('Using let in setTimeout loop:');
for (let j = 0; j < 3; j++) {
  setTimeout(function () {
    console.log('  let j:', j); // Correctly prints 0, 1, 2
  }, 20);
}

// Wait for setTimeouts to complete before continuing
setTimeout(() => {
  console.log('\n=== TEMPORAL DEAD ZONE (TDZ) ===\n');

  // TDZ demonstration
  function tdzDemo() {
    // TDZ starts for 'x'
    const result = typeof undeclaredVar; // OK - not in TDZ
    console.log('typeof undeclaredVar:', result); // "undefined"

    // const resultX = typeof x; // ReferenceError! x is in TDZ

    let x = 10; // TDZ ends for x
    console.log('x after TDZ:', x);
  }
  tdzDemo();

  // ============================================
  // PRACTICAL EXAMPLES
  // ============================================

  console.log('\n=== PRACTICAL EXAMPLES ===\n');

  // Example 1: Configuration object (use const)
  const CONFIG = {
    apiUrl: 'https://api.example.com',
    timeout: 3000,
    debug: true,
  };
  console.log('Config:', CONFIG);
  // Can still modify properties
  CONFIG.debug = false;
  console.log('Modified config:', CONFIG);

  // Example 2: Counter (use let)
  let counter = 0;
  function increment() {
    counter++;
    return counter;
  }
  console.log('\nCounter:', increment()); // 1
  console.log('Counter:', increment()); // 2
  console.log('Counter:', increment()); // 3

  // Example 3: Constants (use const with UPPER_CASE)
  const MAX_USERS = 100;
  const MIN_PASSWORD_LENGTH = 8;
  const API_KEY = 'abc123xyz';

  console.log('\nConstants:');
  console.log('  MAX_USERS:', MAX_USERS);
  console.log('  MIN_PASSWORD_LENGTH:', MIN_PASSWORD_LENGTH);

  // Example 4: Reference that changes (use let)
  let currentUser = { name: 'John' };
  console.log('\nCurrent user:', currentUser);
  currentUser = { name: 'Jane' }; // Reassignment
  console.log('After reassignment:', currentUser);

  // Example 5: Reference that never changes (use const)
  const user = { name: 'Bob' };
  user.name = 'Robert'; // Mutation, not reassignment - OK
  console.log('\nMutated const object:', user);
}, 100);

// ============================================
// HOISTING COMPARISON
// ============================================

console.log('\n=== HOISTING COMPARISON ===\n');

// var hoisting - accessible but undefined
console.log('var before declaration:', typeof varHoist); // "undefined"
var varHoist = 'Hello';

// let hoisting - in TDZ, typeof throws error
// console.log("let before declaration:", typeof letHoist); // ReferenceError
let letHoist = 'Hello';

// Function hoisting - fully hoisted
console.log('Function before declaration:', hoistedFunc()); // Works!
function hoistedFunc() {
  return "I'm hoisted!";
}

// ============================================
// COMMON MISTAKES AND FIXES
// ============================================

console.log('\n=== COMMON MISTAKES ===\n');

// Mistake 1: Using var in loops
console.log('Mistake 1 - var in loop (creates shared variable):');
var buttons = [];
for (var k = 0; k < 3; k++) {
  buttons[k] = function () {
    return k;
  };
}
console.log('  All buttons return:', buttons[0](), buttons[1](), buttons[2]()); // 3, 3, 3

console.log('\nFix - let in loop (creates new variable each iteration):');
let fixedButtons = [];
for (let k = 0; k < 3; k++) {
  fixedButtons[k] = function () {
    return k;
  };
}
console.log(
  '  Buttons return:',
  fixedButtons[0](),
  fixedButtons[1](),
  fixedButtons[2]()
); // 0, 1, 2

// Mistake 2: Thinking const means immutable
console.log('\nMistake 2 - Thinking const is immutable:');
const immutableMisconception = [1, 2, 3];
immutableMisconception.push(4); // This works!
console.log("  Mutated 'const' array:", immutableMisconception);

// Mistake 3: Declaring without initialization when using const
// const needsValue; // SyntaxError
console.log(
  '\nMistake 3 - const needs initialization (would cause SyntaxError)'
);

// ============================================
// BEST PRACTICES SUMMARY
// ============================================

console.log('\n=== BEST PRACTICES ===\n');

console.log('1. Default to const');
const defaultToConst = 'This is the default choice';
console.log('  ', defaultToConst);

console.log('\n2. Use let only when reassignment is needed');
let needsReassignment = 'initial';
needsReassignment = 'changed';
console.log('  ', needsReassignment);

console.log('\n3. Never use var');
console.log('   var is legacy - avoid it in modern code');

console.log('\n4. One declaration per line');
const item1 = 'apple';
const item2 = 'banana';
const item3 = 'cherry';
console.log('  ', item1, item2, item3);

console.log('\n5. Use meaningful names');
const userAccountBalance = 1000;
const isUserLoggedIn = true;
const MAXIMUM_RETRY_ATTEMPTS = 3;
console.log('   Good names are self-documenting');
Examples - JavaScript Tutorial | DeepML