Function Declarations, Expressions, and Arrow Functions

Three syntaxes for creating a function value, differing in hoisting behavior and how they handle this.

                function name() {} / const name = function () {} / const name = () => {}
              

Purpose

JavaScript has three ways to write a function value, differing mainly in hoisting and in how each handles this (covered in depth in the Intermediate tier).

Syntax

function add(a, b) {
  return a + b;
}

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

const multiply = (a, b) => a * b;

Behavior notes

  • A function declaration is hoisted — the whole function is available before its own line executes, anywhere in its enclosing scope.
  • A function expression (assigned to a binding) is only callable after that line executes, like any other const/let value.
  • An arrow function is always an expression, never a declaration. It cannot be used as a constructor (new arrowFn() throws), and it does not have its own this, arguments, or super — it uses the enclosing scope’s.
  • An arrow function with a single expression body (no { }) implicitly returns that expression’s value; one with a block body ({ }) needs an explicit return.

Common mistakes

  • Calling a function expression before the line that defines it, expecting declaration-style hoisting — this throws a ReferenceError (or TypeError if the binding exists but isn’t yet assigned).
  • Using an arrow function where a method needing its own this was intended — this becomes relevant once objects and classes are introduced in the Intermediate tier.

Runtime notes

All three forms are core ECMAScript (arrow functions since ES2015) with identical behavior across browsers and Node.

Taught in these lessons

Related reference