Docs

5.2-Function-Expressions

5.2 Function Expressions

Overview

A function expression is an alternative way to define functions in JavaScript. Unlike function declarations, function expressions are not hoisted, and the function is created when the execution reaches that line. Function expressions can be anonymous or named.


Table of Contents

  1. •Function Expression Syntax
  2. •Anonymous vs Named Functions
  3. •Hoisting Differences
  4. •When to Use Function Expressions
  5. •IIFE - Immediately Invoked Function Expressions
  6. •Callback Functions
  7. •Higher-Order Functions
  8. •Function Expression Patterns
  9. •Best Practices

Function Expression Syntax

Basic Syntax

const functionName = function (parameters) {
  // Function body
  return value;
};

Comparison with Declaration

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│         Function Declaration vs Expression               │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                          │
│  Declaration:                   Expression:              │
│  ───────────                    ───────────              │
│                                                          │
│  function greet(name) {         const greet = function(name) {
│      return "Hi " + name;           return "Hi " + name;
│  }                              };                       │
│                                                          │
│  • Hoisted                      • NOT hoisted            │
│  • Has own name                 • Anonymous or named     │
│  • Statement                    • Expression (value)     │
│                                                          │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Examples

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

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

// Using the functions
console.log(add(5, 3)); // 8
console.log(subtract(5, 3)); // 2

Anonymous vs Named Functions

Anonymous Function Expression

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

// The function has no intrinsic name
console.log(greet.name); // "greet" (inferred from variable)

Named Function Expression

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

console.log(greet.name); // "sayHello"
// sayHello("World");        // Error: sayHello is not defined
greet('World'); // "Hello, World"

Benefits of Named Function Expressions

BenefitDescription
Stack tracesError messages show the function name
RecursionFunction can call itself by name
DebuggingEasier to identify in dev tools
Self-documentationCode is more readable

Recursion with Named Expressions

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

console.log(factorial(5)); // 120
// console.log(fact(5));    // Error: fact is not defined

Hoisting Differences

Function Declaration - Hoisted

// Works - declaration is hoisted
sayHello();

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

Function Expression - NOT Hoisted

// Error: Cannot access 'sayHi' before initialization
// sayHi();

const sayHi = function () {
  console.log('Hi!');
};

sayHi(); // Works after definition

Variable Hoisting with var

console.log(greet); // undefined (var is hoisted but not initialized)
// greet();          // TypeError: greet is not a function

var greet = function () {
  return 'Hello';
};

greet(); // Works

Temporal Dead Zone with let/const

// console.log(greet);  // ReferenceError: Cannot access before initialization

const greet = function () {
  return 'Hello';
};

When to Use Function Expressions

1. Callbacks

setTimeout(function () {
  console.log('Executed after 1 second');
}, 1000);

[1, 2, 3].map(function (num) {
  return num * 2;
});

2. Conditional Function Creation

let operation;

if (mode === 'add') {
  operation = function (a, b) {
    return a + b;
  };
} else {
  operation = function (a, b) {
    return a - b;
  };
}

3. Passing Functions as Values

const handlers = {
  success: function (data) {
    console.log('Success:', data);
  },
  error: function (err) {
    console.log('Error:', err);
  },
};

4. Immediately Invoked (IIFE)

const result = (function (x) {
  return x * x;
})(5);

5. Closures

const counter = (function () {
  let count = 0;
  return function () {
    return ++count;
  };
})();

IIFE - Immediately Invoked Function Expressions

An IIFE is a function expression that runs immediately after being defined.

Syntax

(function () {
  // Code executed immediately
})();

// Alternative syntax
(function () {
  // Code executed immediately
})();

With Parameters

(function (name) {
  console.log('Hello, ' + name);
})('World');

Named IIFE

(function init() {
  console.log('Initializing...');
  // Initialization code
})();

Use Cases

// 1. Create private scope
(function () {
  const privateVar = 'secret';
  // privateVar is not accessible outside
})();

// 2. Avoid polluting global scope
(function (global) {
  global.myApp = {
    version: '1.0.0',
  };
})(window);

// 3. Module pattern
const module = (function () {
  const private = 'hidden';

  return {
    getPrivate: function () {
      return private;
    },
  };
})();

console.log(module.getPrivate()); // "hidden"
// console.log(module.private);    // undefined

Callback Functions

A callback is a function passed as an argument to another function.

Basic Callback

function processData(data, callback) {
  const result = data.toUpperCase();
  callback(result);
}

const logResult = function (result) {
  console.log('Result:', result);
};

processData('hello', logResult);
// "Result: HELLO"

Inline Callbacks

processData('hello', function (result) {
  console.log('Inline result:', result);
});

Callback with Multiple Functions

function fetchData(onSuccess, onError) {
  const success = Math.random() > 0.5;

  if (success) {
    onSuccess({ data: [1, 2, 3] });
  } else {
    onError(new Error('Failed to fetch'));
  }
}

fetchData(
  function (data) {
    console.log('Success:', data);
  },
  function (error) {
    console.log('Error:', error.message);
  }
);

Higher-Order Functions

Functions that take functions as arguments or return functions.

Taking Functions as Arguments

function repeat(n, action) {
  for (let i = 0; i < n; i++) {
    action(i);
  }
}

repeat(3, function (i) {
  console.log('Iteration:', i);
});

Returning Functions

function createGreeter(greeting) {
  return function (name) {
    return greeting + ', ' + name + '!';
  };
}

const sayHello = createGreeter('Hello');
const sayHi = createGreeter('Hi');

console.log(sayHello('Alice')); // "Hello, Alice!"
console.log(sayHi('Bob')); // "Hi, Bob!"

Function Composition

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

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

const addOneThenDouble = compose(double, addOne);
console.log(addOneThenDouble(5)); // 12 (5+1=6, 6*2=12)

Function Expression Patterns

1. Module Pattern

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

  // Public interface
  return {
    add: function (n) {
      result += n;
      return this;
    },
    subtract: function (n) {
      result -= n;
      return this;
    },
    multiply: function (n) {
      result *= n;
      return this;
    },
    getResult: function () {
      return result;
    },
    reset: function () {
      result = 0;
      return this;
    },
  };
})();

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

2. Factory Pattern

const createPerson = function (name, age) {
  return {
    name: name,
    age: age,
    greet: function () {
      return "Hi, I'm " + this.name;
    },
  };
};

const person = createPerson('Alice', 30);
console.log(person.greet()); // "Hi, I'm Alice"

3. Revealing Module Pattern

const userModule = (function () {
  let users = [];

  function add(user) {
    users.push(user);
  }

  function getAll() {
    return [...users];
  }

  function findById(id) {
    return users.find(function (u) {
      return u.id === id;
    });
  }

  return {
    add: add,
    getAll: getAll,
    findById: findById,
  };
})();

4. Singleton Pattern

const Database = (function () {
  let instance;

  function createInstance() {
    return {
      connection: 'Connected',
      query: function (sql) {
        console.log('Executing:', sql);
      },
    };
  }

  return {
    getInstance: function () {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    },
  };
})();

const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true (same instance)

Best Practices

1. Use const for Function Expressions

// āœ… Prevents reassignment
const greet = function (name) {
  return 'Hello, ' + name;
};

// āŒ Can be reassigned accidentally
let greet = function (name) {
  return 'Hello, ' + name;
};

2. Name Complex Functions

// āŒ Hard to debug
element.addEventListener('click', function (e) {
  // Complex logic
});

// āœ… Easier to debug
element.addEventListener('click', function handleClick(e) {
  // Complex logic
});

3. Extract Repeated Callbacks

// āŒ Repeated anonymous functions
[1, 2, 3].map(function (x) {
  return x * 2;
});
[4, 5, 6].map(function (x) {
  return x * 2;
});

// āœ… Reusable named function
const double = function (x) {
  return x * 2;
};
[1, 2, 3].map(double);
[4, 5, 6].map(double);

4. Use Declarations for Top-Level Functions

// āœ… Use declaration for main functions
function processOrder(order) {
  // Main business logic
}

// āœ… Use expression for callbacks/helpers
const formatPrice = function (price) {
  return '$' + price.toFixed(2);
};

5. Prefer Arrow Functions for Simple Callbacks

// āŒ Verbose for simple operations
[1, 2, 3].map(function (x) {
  return x * 2;
});

// āœ… Concise arrow function
[1, 2, 3].map((x) => x * 2);

Summary

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│          Function Expressions Quick Reference            │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│                                                          │
│  // Anonymous expression                                 │
│  const add = function(a, b) { return a + b; };          │
│                                                          │
│  // Named expression                                     │
│  const add = function sum(a, b) { return a + b; };      │
│                                                          │
│  // IIFE                                                 │
│  (function() { /* runs immediately */ })();              │
│                                                          │
│  Key Differences from Declarations:                      │
│  • NOT hoisted                                           │
│  • Can be anonymous                                      │
│  • Are expressions (values)                              │
│  • Better for callbacks                                  │
│                                                          │
│  Common Uses:                                            │
│  • Callbacks                                             │
│  • IIFE for private scope                                │
│  • Higher-order functions                                │
│  • Module pattern                                        │
│  • Conditional function creation                         │
│                                                          │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

Next Steps

  • •Practice with the examples in examples.js
  • •Complete the exercises in exercises.js
  • •Learn about arrow functions in the next topic
  • •Explore closures and scope in depth
.2 Function Expressions - JavaScript Tutorial | DeepML