javascript

examples

examples.js
/**
 * =====================================================
 * 5.2 FUNCTION EXPRESSIONS - EXAMPLES
 * =====================================================
 * Alternative way to define functions
 */

// =====================================================
// 1. BASIC FUNCTION EXPRESSION
// =====================================================

console.log('--- Basic Function Expression ---');

const greet = function (name) {
  return 'Hello, ' + name + '!';
};

console.log(greet('Alice'));
console.log(greet('Bob'));

// =====================================================
// 2. ANONYMOUS VS NAMED EXPRESSIONS
// =====================================================

console.log('\n--- Anonymous vs Named ---');

// Anonymous
const add = function (a, b) {
  return a + b;
};

// Named
const subtract = function sub(a, b) {
  return a - b;
};

console.log('add.name:', add.name); // "add" (inferred)
console.log('subtract.name:', subtract.name); // "sub"

// =====================================================
// 3. NAMED EXPRESSION FOR RECURSION
// =====================================================

console.log('\n--- Recursion with Named Expression ---');

const factorial = function fact(n) {
  if (n <= 1) return 1;
  return n * fact(n - 1); // Uses internal name
};

console.log('5! =', factorial(5));
console.log('10! =', factorial(10));

// The internal name 'fact' is only accessible inside
// console.log(fact(5));  // Error: fact is not defined

// =====================================================
// 4. HOISTING DIFFERENCES
// =====================================================

console.log('\n--- Hoisting Differences ---');

// Function declaration - hoisted
console.log('Declaration (hoisted):', declaredFunc());

function declaredFunc() {
  return "I'm hoisted!";
}

// Function expression - NOT hoisted
// console.log(expressedFunc());  // Error!

const expressedFunc = function () {
  return "I'm NOT hoisted!";
};

console.log('Expression (after definition):', expressedFunc());

// =====================================================
// 5. IIFE - IMMEDIATELY INVOKED FUNCTION EXPRESSION
// =====================================================

console.log('\n--- IIFE ---');

// Basic IIFE
(function () {
  console.log('IIFE executed immediately!');
})();

// IIFE with parameters
const result = (function (a, b) {
  return a + b;
})(10, 20);

console.log('IIFE result:', result);

// Named IIFE
(function init() {
  console.log('Initialization complete');
})();

// =====================================================
// 6. IIFE FOR PRIVATE SCOPE
// =====================================================

console.log('\n--- IIFE for Private Scope ---');

const counter = (function () {
  let count = 0; // Private variable

  return {
    increment: function () {
      count++;
      return count;
    },
    decrement: function () {
      count--;
      return count;
    },
    getCount: function () {
      return count;
    },
  };
})();

console.log('Initial:', counter.getCount());
console.log('After increment:', counter.increment());
console.log('After increment:', counter.increment());
console.log('After decrement:', counter.decrement());
// console.log(count);  // Error: count is not defined (private)

// =====================================================
// 7. CALLBACK FUNCTIONS
// =====================================================

console.log('\n--- Callback Functions ---');

function processArray(arr, callback) {
  const results = [];
  for (const item of arr) {
    results.push(callback(item));
  }
  return results;
}

// Using function expression as callback
const double = function (x) {
  return x * 2;
};

const square = function (x) {
  return x * x;
};

const numbers = [1, 2, 3, 4, 5];
console.log('Doubled:', processArray(numbers, double));
console.log('Squared:', processArray(numbers, square));

// Inline anonymous callback
console.log(
  'Tripled:',
  processArray(numbers, function (x) {
    return x * 3;
  })
);

// =====================================================
// 8. HIGHER-ORDER FUNCTIONS
// =====================================================

console.log('\n--- Higher-Order Functions ---');

// Function that returns a function
function createMultiplier(factor) {
  return function (number) {
    return number * factor;
  };
}

const triple = createMultiplier(3);
const quadruple = createMultiplier(4);

console.log('triple(10):', triple(10));
console.log('quadruple(10):', quadruple(10));

// Function that takes multiple callbacks
function conditional(value, onTrue, onFalse) {
  return value ? onTrue() : onFalse();
}

const result2 = conditional(
  true,
  function () {
    return 'It was true';
  },
  function () {
    return 'It was false';
  }
);
console.log('Conditional result:', result2);

// =====================================================
// 9. FUNCTION COMPOSITION
// =====================================================

console.log('\n--- Function Composition ---');

const compose = function (f, g) {
  return function (x) {
    return f(g(x));
  };
};

const addOne = function (x) {
  return x + 1;
};
const doubleNum = function (x) {
  return x * 2;
};
const squareNum = function (x) {
  return x * x;
};

const addOneThenDouble = compose(doubleNum, addOne);
const doubleThenSquare = compose(squareNum, doubleNum);

console.log('addOneThenDouble(5):', addOneThenDouble(5)); // (5+1)*2 = 12
console.log('doubleThenSquare(3):', doubleThenSquare(3)); // (3*2)² = 36

// =====================================================
// 10. MODULE PATTERN
// =====================================================

console.log('\n--- Module Pattern ---');

const calculator = (function () {
  // Private state
  let memory = 0;

  // Private function
  function log(operation, value) {
    console.log(`  ${operation}: ${value}, Memory: ${memory}`);
  }

  // Public interface
  return {
    add: function (n) {
      memory += n;
      log('Add', n);
      return this;
    },
    subtract: function (n) {
      memory -= n;
      log('Subtract', n);
      return this;
    },
    multiply: function (n) {
      memory *= n;
      log('Multiply', n);
      return this;
    },
    getResult: function () {
      return memory;
    },
    clear: function () {
      memory = 0;
      log('Clear', 0);
      return this;
    },
  };
})();

calculator.add(10).multiply(2).subtract(5).add(3);

console.log('Final result:', calculator.getResult());

// =====================================================
// 11. FACTORY FUNCTION
// =====================================================

console.log('\n--- Factory Function ---');

const createUser = function (name, role) {
  // Private
  let loginCount = 0;

  // Public
  return {
    name: name,
    role: role,
    login: function () {
      loginCount++;
      console.log(`${name} logged in. Total logins: ${loginCount}`);
    },
    getLoginCount: function () {
      return loginCount;
    },
  };
};

const user1 = createUser('Alice', 'admin');
const user2 = createUser('Bob', 'user');

user1.login();
user1.login();
user2.login();

console.log('Alice logins:', user1.getLoginCount());
console.log('Bob logins:', user2.getLoginCount());

// =====================================================
// 12. CONDITIONAL FUNCTION CREATION
// =====================================================

console.log('\n--- Conditional Function Creation ---');

function createFormatter(type) {
  if (type === 'uppercase') {
    return function (str) {
      return str.toUpperCase();
    };
  } else if (type === 'lowercase') {
    return function (str) {
      return str.toLowerCase();
    };
  } else {
    return function (str) {
      return str;
    };
  }
}

const uppercase = createFormatter('uppercase');
const lowercase = createFormatter('lowercase');

console.log(uppercase('Hello World'));
console.log(lowercase('Hello World'));

// =====================================================
// 13. STORING FUNCTIONS IN DATA STRUCTURES
// =====================================================

console.log('\n--- Functions in Data Structures ---');

// Array of functions
const operations = [
  function (x) {
    return x + 10;
  },
  function (x) {
    return x * 2;
  },
  function (x) {
    return x - 5;
  },
];

let value = 10;
for (const op of operations) {
  value = op(value);
  console.log('Value:', value);
}

// Object of functions
const handlers = {
  click: function (e) {
    console.log('Clicked!');
  },
  hover: function (e) {
    console.log('Hovered!');
  },
  keypress: function (e) {
    console.log('Key pressed!');
  },
};

handlers.click();
handlers.hover();

// =====================================================
// 14. FUNCTION EXPRESSION AS METHOD
// =====================================================

console.log('\n--- Function Expression as Method ---');

const person = {
  name: 'Charlie',
  greet: function () {
    return "Hi, I'm " + this.name;
  },
  // ES6 shorthand (also a function expression internally)
  wave() {
    return this.name + ' waves!';
  },
};

console.log(person.greet());
console.log(person.wave());

// =====================================================
// 15. PRACTICAL EXAMPLE: EVENT HANDLER PATTERN
// =====================================================

console.log('\n--- Event Handler Pattern ---');

const EventEmitter = (function () {
  const events = {};

  return {
    on: function (event, handler) {
      if (!events[event]) {
        events[event] = [];
      }
      events[event].push(handler);
    },
    emit: function (event, data) {
      if (events[event]) {
        events[event].forEach(function (handler) {
          handler(data);
        });
      }
    },
    off: function (event, handler) {
      if (events[event]) {
        events[event] = events[event].filter(function (h) {
          return h !== handler;
        });
      }
    },
  };
})();

// Register handlers
const logHandler = function (data) {
  console.log('Event data:', data);
};

EventEmitter.on('message', logHandler);
EventEmitter.on('message', function (data) {
  console.log('Another handler:', data.toUpperCase());
});

// Emit event
EventEmitter.emit('message', 'Hello!');

// =====================================================
// SUMMARY
// =====================================================

console.log('\n--- Summary ---');
console.log(`
Function Expressions:
  • const fn = function() {};
  • NOT hoisted
  • Can be anonymous or named
  
Named Expressions:
  • Better stack traces
  • Enable recursion
  • Self-documenting

IIFE:
  • (function() { })();
  • Runs immediately
  • Creates private scope

Common Patterns:
  • Module pattern
  • Factory functions
  • Callbacks
  • Higher-order functions
`);
Examples - JavaScript Tutorial | DeepML