javascript

examples

examples.js
/**
 * =====================================================
 * 5.3 ARROW FUNCTIONS - EXAMPLES
 * =====================================================
 * Modern, concise function syntax
 */

// =====================================================
// 1. BASIC ARROW FUNCTION SYNTAX
// =====================================================

console.log('--- Basic Arrow Function Syntax ---');

// Traditional function expression
const traditionalGreet = function (name) {
  return 'Hello, ' + name;
};

// Arrow function
const arrowGreet = (name) => {
  return 'Hello, ' + name;
};

// Concise arrow function
const conciseGreet = (name) => 'Hello, ' + name;

console.log(traditionalGreet('Alice'));
console.log(arrowGreet('Bob'));
console.log(conciseGreet('Charlie'));

// =====================================================
// 2. SYNTAX VARIATIONS
// =====================================================

console.log('\n--- Syntax Variations ---');

// No parameters - parentheses required
const sayHello = () => 'Hello!';
console.log('No params:', sayHello());

// One parameter - parentheses optional
const double = (x) => x * 2;
const doubleWithParens = (x) => x * 2;
console.log('One param:', double(5));

// Multiple parameters - parentheses required
const add = (a, b) => a + b;
console.log('Multiple params:', add(3, 4));

// With block body - needs explicit return
const calculate = (a, b) => {
  const sum = a + b;
  const product = a * b;
  return { sum, product };
};
console.log('Block body:', calculate(3, 4));

// =====================================================
// 3. IMPLICIT VS EXPLICIT RETURN
// =====================================================

console.log('\n--- Implicit vs Explicit Return ---');

// Implicit return (expression body)
const square = (x) => x * x;
const isEven = (n) => n % 2 === 0;
const getFirst = (arr) => arr[0];

console.log('square(4):', square(4));
console.log('isEven(4):', isEven(4));
console.log('getFirst([1,2,3]):', getFirst([1, 2, 3]));

// Explicit return (block body)
const squareExplicit = (x) => {
  return x * x;
};

// =====================================================
// 4. RETURNING OBJECTS
// =====================================================

console.log('\n--- Returning Objects ---');

// Wrap object literal in parentheses
const makeUser = (name, age) => ({ name, age });
console.log('makeUser:', makeUser('Alice', 25));

// Multi-line object return
const createPerson = (name, age) => ({
  name,
  age,
  isAdult: age >= 18,
  greet() {
    return `Hi, I'm ${name}`;
  },
});

const person = createPerson('Bob', 30);
console.log('createPerson:', person);
console.log('greet:', person.greet());

// =====================================================
// 5. DEFAULT AND REST PARAMETERS
// =====================================================

console.log('\n--- Default and Rest Parameters ---');

// Default parameters
const greetWithDefault = (name = 'Guest') => `Hello, ${name}!`;
console.log(greetWithDefault());
console.log(greetWithDefault('Alice'));

// Rest parameters
const sum = (...numbers) => numbers.reduce((a, b) => a + b, 0);
console.log('sum(1,2,3,4,5):', sum(1, 2, 3, 4, 5));

// Combining default and rest
const logMessage = (prefix = 'LOG', ...messages) => {
  messages.forEach((msg) => console.log(`[${prefix}] ${msg}`));
};
logMessage('INFO', 'Starting', 'Processing', 'Done');

// =====================================================
// 6. ARROW FUNCTIONS WITH ARRAY METHODS
// =====================================================

console.log('\n--- Array Methods ---');

const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// map
const doubled = numbers.map((n) => n * 2);
console.log('doubled:', doubled);

// filter
const evens = numbers.filter((n) => n % 2 === 0);
console.log('evens:', evens);

// reduce
const total = numbers.reduce((acc, n) => acc + n, 0);
console.log('total:', total);

// find
const firstBig = numbers.find((n) => n > 7);
console.log('firstBig:', firstBig);

// every / some
const allPositive = numbers.every((n) => n > 0);
const hasEven = numbers.some((n) => n % 2 === 0);
console.log('allPositive:', allPositive, 'hasEven:', hasEven);

// Chaining
const result = numbers
  .filter((n) => n % 2 === 0)
  .map((n) => n * 3)
  .reduce((acc, n) => acc + n, 0);
console.log('chained result:', result);

// =====================================================
// 7. THE 'this' KEYWORD - KEY DIFFERENCE
// =====================================================

console.log("\n--- The 'this' Keyword ---");

// Regular function - dynamic 'this'
const regularObj = {
  name: 'Regular Object',
  regularMethod: function () {
    console.log('Regular method this.name:', this.name);

    // Inner function loses 'this'
    const inner = function () {
      console.log('Inner regular this.name:', this?.name || 'undefined');
    };
    inner();
  },
};

regularObj.regularMethod();

// Arrow function - lexical 'this'
const arrowObj = {
  name: 'Arrow Object',
  arrowMethod: function () {
    console.log('Arrow method this.name:', this.name);

    // Arrow preserves 'this'
    const inner = () => {
      console.log('Inner arrow this.name:', this.name);
    };
    inner();
  },
};

arrowObj.arrowMethod();

// =====================================================
// 8. ARROW FUNCTIONS IN CALLBACKS
// =====================================================

console.log('\n--- Arrow in Callbacks ---');

const timer = {
  seconds: 0,
  start: function () {
    // Arrow function preserves 'this'
    const intervalId = setInterval(() => {
      this.seconds++;
      console.log(`Timer: ${this.seconds}s`);
      if (this.seconds >= 3) {
        clearInterval(intervalId);
        console.log('Timer stopped');
      }
    }, 100);
  },
};

// Uncomment to test
// timer.start();

// Simulated example
const callbackDemo = {
  value: 42,
  process: function () {
    const callback = () => {
      console.log('Callback has access to this.value:', this.value);
    };
    callback();
  },
};
callbackDemo.process();

// =====================================================
// 9. CURRYING WITH ARROW FUNCTIONS
// =====================================================

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

// Curried multiply
const multiply = (a) => (b) => a * b;

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

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

// Curried add with multiple levels
const addThree = (a) => (b) => (c) => a + b + c;
console.log('addThree(1)(2)(3):', addThree(1)(2)(3));

// Practical currying
const greetPerson = (greeting) => (name) => `${greeting}, ${name}!`;
const sayHi = greetPerson('Hi');
const sayHey = greetPerson('Hey');

console.log(sayHi('Alice'));
console.log(sayHey('Bob'));

// =====================================================
// 10. FUNCTION COMPOSITION
// =====================================================

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

// Compose (right to left)
const compose =
  (...fns) =>
  (x) =>
    fns.reduceRight((acc, fn) => fn(acc), x);

// Pipe (left to right)
const pipe =
  (...fns) =>
  (x) =>
    fns.reduce((acc, fn) => fn(acc), x);

const addOne = (x) => x + 1;
const doubleNum = (x) => x * 2;
const squareNum = (x) => x * x;

const composed = compose(squareNum, doubleNum, addOne);
const piped = pipe(addOne, doubleNum, squareNum);

console.log('compose (right to left) of 2:', composed(2)); // ((2+1)*2)² = 36
console.log('pipe (left to right) of 2:', piped(2)); // ((2+1)*2)² = 36

// =====================================================
// 11. WHEN NOT TO USE ARROW FUNCTIONS
// =====================================================

console.log('\n--- When NOT to Use Arrow Functions ---');

// ❌ Object methods (arrow loses 'this')
const badObject = {
  value: 100,
  getValue: () => {
    console.log('Bad getValue this:', this?.value || 'undefined');
  },
};
badObject.getValue();

// ✅ Use regular function or shorthand
const goodObject = {
  value: 100,
  getValue() {
    console.log('Good getValue this:', this.value);
  },
};
goodObject.getValue();

// ❌ Cannot use as constructor
const ArrowPerson = (name) => {
  this.name = name;
};
// const p = new ArrowPerson("Alice");  // TypeError!

// =====================================================
// 12. ARROW FUNCTIONS WITH TERNARY OPERATORS
// =====================================================

console.log('\n--- Ternary Operators ---');

const abs = (n) => (n >= 0 ? n : -n);
const max = (a, b) => (a > b ? a : b);
const min = (a, b) => (a < b ? a : b);
const clamp = (n, lo, hi) => (n < lo ? lo : n > hi ? hi : n);

console.log('abs(-5):', abs(-5));
console.log('max(3, 7):', max(3, 7));
console.log('min(3, 7):', min(3, 7));
console.log('clamp(15, 0, 10):', clamp(15, 0, 10));

// =====================================================
// 13. PRACTICAL EXAMPLES
// =====================================================

console.log('\n--- Practical Examples ---');

const users = [
  { name: 'Alice', age: 25, active: true },
  { name: 'Bob', age: 30, active: false },
  { name: 'Charlie', age: 22, active: true },
  { name: 'Diana', age: 35, active: true },
];

// Get active users
const activeUsers = users.filter((u) => u.active);
console.log(
  'Active users:',
  activeUsers.map((u) => u.name)
);

// Get average age
const avgAge = users.reduce((acc, u) => acc + u.age, 0) / users.length;
console.log('Average age:', avgAge);

// Sort by age
const sortedByAge = [...users].sort((a, b) => a.age - b.age);
console.log(
  'Sorted by age:',
  sortedByAge.map((u) => `${u.name}:${u.age}`)
);

// Find user by name
const findByName = (name) => users.find((u) => u.name === name);
console.log('Find Diana:', findByName('Diana'));

// =====================================================
// 14. PROMISE CHAINS WITH ARROWS
// =====================================================

console.log('\n--- Promise Chains ---');

// Simulated async operations
const fetchData = () => Promise.resolve({ items: [1, 2, 3] });
const processItems = (items) => items.map((i) => i * 2);
const filterItems = (items) => items.filter((i) => i > 2);

fetchData()
  .then((data) => data.items)
  .then((items) => processItems(items))
  .then((items) => filterItems(items))
  .then((result) => console.log('Promise chain result:', result))
  .catch((error) => console.error('Error:', error));

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

console.log('\n--- Summary ---');
console.log(`
Arrow Function Syntax:
  • () => expression         (no params)
  • x => expression          (one param)
  • (x, y) => expression     (multiple params)
  • (x, y) => { return v; }  (block body)
  • x => ({ key: value })    (return object)

Key Differences:
  • Lexical 'this' (inherits from enclosing scope)
  • No 'arguments' object (use rest params)
  • Cannot be used with 'new'
  • No 'prototype' property

Best For:
  • Array methods (map, filter, reduce)
  • Callbacks needing 'this' preservation
  • Promise chains
  • Short, single-expression functions

Avoid For:
  • Object methods
  • Constructors
  • Dynamic 'this' needs
  • Prototype methods
`);
Examples - JavaScript Tutorial | DeepML