JavaScript Functions

Beginner 7 min read

Functions are reusable blocks of code that perform specific tasks. They are fundamental to JavaScript and can be defined in multiple ways: declarations, expressions, and arrow functions.

Function Declaration

The traditional way to define a function using the function keyword:

javascript
// Function Declaration
function greet(name) {
  return "Hello, " + name + "!";
}

// Can be called before declaration (hoisted)
sayHello(); // Works!

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

// Parameters and return value
function add(a, b) {
  return a + b;  // Returns the sum
}

const result = add(2, 3);  // result = 5
Hoisting
Function declarations are hoisted to the top of their scope. You can call them before they appear in your code.

Function Expression

A function assigned to a variable:

javascript
// Function Expression
const greet = function(name) {
  return "Hello, " + name + "!";
};

// Named function expression (useful for recursion/debugging)
const factorial = function fact(n) {
  if (n <= 1) return 1;
  return n * fact(n - 1);
};

// Cannot be called before definition
// multiply(2, 3); // Error!
const multiply = function(a, b) {
  return a * b;
};
Warning
Function expressions are NOT hoisted. You must define them before calling them.

Arrow Functions

A shorter syntax introduced in ES6. Arrow functions are ideal for callbacks and do not have their own this binding:

javascript
// Arrow Function (ES6)
const greet = (name) => {
  return "Hello, " + name + "!";
};

// Short syntax (implicit return)
const add = (a, b) => a + b;

// Single parameter (parentheses optional)
const double = x => x * 2;

// No parameters (parentheses required)
const sayHi = () => "Hi!";

// Returning an object (wrap in parentheses)
const createUser = (name) => ({ name, id: Date.now() });

// Arrow functions and "this"
const obj = {
  name: "Alice",
  // Regular function - "this" is obj
  greet: function() {
    console.log("Hello, " + this.name);
  },
  // Arrow - "this" is inherited (not obj!)
  greetArrow: () => {
    console.log("Hello, " + this.name); // this.name is undefined
  }
};
When to Use Arrow Functions
Use arrow functions for callbacks, array methods, and short functions. Avoid them for object methods where you need access to this.

Comparison

FeatureDeclarationExpressionArrow
Hoisted
NamedOptional
Own this
Can be constructor
arguments object

The Return Statement

Use return to send a value back from a function and end execution:

javascript
// Explicit return
function add(a, b) {
  return a + b;  // Execution stops here
  console.log("Never runs");
}

// No return = undefined
function noReturn() {
  console.log("Hello");
  // Implicitly returns undefined
}

// Early return for validation
function divide(a, b) {
  if (b === 0) {
    return "Error: Division by zero";
  }
  return a / b;
}

// Return multiple values (use object or array)
function getMinMax(arr) {
  return {
    min: Math.min(...arr),
    max: Math.max(...arr)
  };
}
const { min, max } = getMinMax([1, 5, 3, 9, 2]);

Try It Yourself

Experiment with different function types:

index.js
// Function Declaration
function greet(name) {
  return "Hello, " + name + "!";
}
console.log(greet("Alice"));

// Function Expression
const add = function(a, b) {
  return a + b;
};
console.log("2 + 3 =", add(2, 3));

// Arrow Function
const multiply = (a, b) => a * b;
console.log("4 * 5 =", multiply(4, 5));

// Arrow function with block body
const divide = (a, b) => {
  if (b === 0) return "Cannot divide by zero";
  return a / b;
};
console.log("10 / 2 =", divide(10, 2));

// Function with default parameters
function greetWithDefault(name = "Guest") {
  return "Welcome, " + name + "!";
}
console.log(greetWithDefault());
console.log(greetWithDefault("Bob"));

Callback Functions

Functions can be passed as arguments to other functions. These are called callbacks:

index.js
// Functions as arguments (callbacks)
function processArray(arr, callback) {
  const result = [];
  for (const item of arr) {
    result.push(callback(item));
  }
  return result;
}

// Using with different callbacks
const numbers = [1, 2, 3, 4, 5];

const doubled = processArray(numbers, x => x * 2);
console.log("Doubled:", doubled);

const squared = processArray(numbers, x => x * x);
console.log("Squared:", squared);

// Built-in array methods with callbacks
const filtered = numbers.filter(x => x > 2);
console.log("Filtered (>2):", filtered);

const sum = numbers.reduce((acc, x) => acc + x, 0);
console.log("Sum:", sum);

// setTimeout callback
console.log("Starting timer...");
setTimeout(() => {
  console.log("Timer finished!");
}, 1000);

Immediately Invoked Function Expression (IIFE)

A function that runs immediately after it is defined:

javascript
// Immediately Invoked Function Expression (IIFE)
(function() {
  console.log("I run immediately!");
})();

// IIFE with arrow function
(() => {
  console.log("Arrow IIFE!");
})();

// IIFE with parameters
(function(name) {
  console.log("Hello, " + name);
})("Alice");

// Use case: Create private scope
const counter = (function() {
  let count = 0;  // Private variable
  return {
    increment: () => ++count,
    decrement: () => --count,
    get: () => count
  };
})();

counter.increment();  // 1
counter.increment();  // 2
counter.get();        // 2
Note
IIFEs were commonly used to create private scopes before ES6 modules. They are still useful for one-time initialization code.

Best Practices

1. Use Descriptive Names
Function names should describe what they do: calculateTotal, validateEmail, fetchUserData.
2. Keep Functions Small
Each function should do one thing well. If a function is too long, break it into smaller functions.
3. Use Arrow Functions for Callbacks
Arrow functions are perfect for array methods and event handlers due to their concise syntax.
4. Avoid Side Effects
Pure functions (same input = same output, no side effects) are easier to test and debug.

Test Your Knowledge

Test Your Knowledge

5 questions
Question 1

What is hoisting in relation to functions?

Question 2

What does an arrow function NOT have?

Question 3

What does a function return if there is no return statement?

Question 4

Which syntax is correct for an arrow function with one parameter?

Question 5

What is a callback function?

Practice Exercise

Function Composition

Medium

Create a compose function that takes multiple functions and returns a new function that applies them right-to-left.

Starter Code
// Challenge: Create a function that composes multiple functions
// compose(f, g, h)(x) should equal f(g(h(x)))

function compose(...functions) {
  // TODO: Return a function that applies all functions right-to-left
}

// Test functions
const addOne = x => x + 1;
const double = x => x * 2;
const square = x => x * x;

// Test compose
const composed = compose(addOne, double, square);
console.log(composed(3));  // Should print 19: (3^2) * 2 + 1 = 9 * 2 + 1 = 19

const composed2 = compose(double, addOne);
console.log(composed2(5)); // Should print 12: (5 + 1) * 2 = 12

Frequently Asked Questions

When should I use arrow functions vs regular functions?

Use arrow functions for callbacks, array methods, and when you need to preserve this from the outer scope. Use regular functions for object methods and constructors where you need their own this.

What is a pure function?

A pure function always returns the same output for the same input and has no side effects (doesn't modify external state). Pure functions are easier to test, debug, and reason about.

Can I have a function inside another function?

Yes! These are called nested functions or inner functions. The inner function has access to the outer function's variables (closure). This is useful for creating private helper functions.

Summary

JavaScript has three ways to define functions:

  • Declaration: function name() {} - hoisted
  • Expression: const name = function() {} - not hoisted
  • Arrow: const name = () => {} - no own this

Key points:

  • Functions can accept parameters and return values
  • Arrow functions are great for callbacks but lack their own this
  • Functions without return return undefined
  • Functions can be passed as arguments (callbacks)