webroad.online
  1. 1Web
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Tooling
  8. 8React
  9. 9State management
  10. 10Next.js
  11. 11Forms
  12. 12Data and backend
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Animations
  16. 16Testing
  17. 17Architecture
JavaScript · Lesson 3 of 17

Functions and closures

Arrow functions, parameters, functions as values, closures.

Updated

What a function is

A function is a named block of code that you write once and run as many times as you want. It receives data (parameters), does something with it and, optionally, gives back a result (return).

Think of it as a recipe: the recipe (the function) is written once; every time you cook (call the function) you can use different ingredients (arguments).

function add(a, b) {   // a, b = parameters (the required ingredients)
  return a + b         // the result
}

add(2, 3)              // 5  — 2 and 3 = arguments (the actual ingredients)
add(10, 20)            // 30

Two different moments you need to be aware of:

Definition Call
Code function add(a, b) { ... } add(2, 3)
What happens JS remembers the recipe, doesn't run it JS runs the function body
How many times once as many as you want

Why functions exist

  • Reuse — you don't copy the same code into 10 places.
  • A name — calculateTotal(cart) says what it does; 15 lines of math don't.
  • Isolation — the variables inside the function don't mix with the rest of the code.
  • Testing — a small function with clear input and output is easy to test.

Parameters and return

function greet(name = 'anonymous') {   // default value
  return `Hello, ${name}`
}

greet()          // 'Hello, anonymous'
greet('Ana')     // 'Hello, Ana'
  • return stops the function and gives back the result. Nothing after it runs.
  • Without return, the function returns undefined.
  • Missing parameters are undefined (unless they have a default value).

Rest parameters and destructuring

const total = (...nums) => nums.reduce((s, n) => s + n, 0)   // any number of arguments → an array
total(1, 2, 3)   // 6

function createUser({ name, role = 'user' }) {                 // you receive an object, you pull out the fields
  return { name, role }
}
createUser({ name: 'Ana' })

More than 3 parameters? Switch to a single object — the order no longer matters and the call reads by itself.

Kinds of functions

1. Function declaration

function sum(a, b) {
  return a + b
}

2. Function expression

const sum = function (a, b) {
  return a + b
}

3. Arrow function

const sum = (a, b) => a + b          // implicit return, a single expression
const square = x => x * x            // one parameter — no parentheses
const getUser = () => ({ id: 1 })    // returning an object — add parentheses
const log = msg => {                 // several lines — braces + an explicit return
  console.log(msg)
}

4. Method (a function inside an object or class)

const cart = {
  items: [],
  add(item) { this.items.push(item) },
}

5. Async function

async function loadUser(id) {
  const res = await fetch(`/api/users/${id}`)
  return res.json()
}

It always returns a Promise — see Async.

The differences that matter

Declaration Expression Arrow Method
Hoisting — you can call it before the line where it's written yes no no —
Its own this yes (depends on the call) yes no — takes this from outside yes = the object
arguments yes yes no yes
Can be used with new yes yes no no
Implicit return no no yes (one expression) no

Which one to use when

Situation The choice
a module's main function, a utility, a React component declaration (function Card() {}) — reads clearly, has hoisting
callbacks: map, filter, onClick, setTimeout, then arrow — short and keeps the outer this
small functions stored in variables, passed around as values arrow
behavior of an object / class that uses this method
anything that uses await async (in any form)
a classic function expression rare today — arrows replaced it

Functions are values

In JS functions are first-class: you can put them in variables, pass them as arguments, return them from other functions.

const shout = text => text.toUpperCase()
['a', 'b'].map(shout)          // passed as an argument → ['A', 'B']

const multiplier = factor => x => x * factor   // returns a function
const double = multiplier(2)
double(5)                      // 10

A function that receives or returns functions is called a higher-order function (map, filter, addEventListener).

Closure

A function remembers the variables from the place where it was created, even after that place has "finished". That's a closure.

function createCounter() {
  let n = 0                // keeps living, "closed" inside the returned function
  return () => ++n
}

const next = createCounter()
next()   // 1
next()   // 2 — n was remembered

const other = createCounter()
other()  // 1 — every call creates a new n

Closures are the basis of useState, React event handlers, debounce, modules.

Pure functions

A function is pure if:

  1. for the same input it always gives the same output;
  2. it has no side effects (doesn't change outside variables, doesn't make requests, doesn't write to the DOM).
const withVat = price => price * 1.19          // ✓ pure

let total = 0
const addToTotal = price => { total += price } // ✗ changes something outside

React components must be pure. So should business logic — it's trivial to test.

Common mistakes

  • Forgetting return (especially in functions with braces) → undefined.
  • An arrow that returns an object without parentheses: () => { id: 1 } returns undefined.
  • Calling instead of passing: onClick={save()} runs immediately; correct is onClick={save} or onClick={() => save(id)}.

Summary

  • A function = named code, defined once, called any number of times; parameters → return.
  • Declarations for main functions, arrows for callbacks, methods for objects.
  • Functions are values; a closure = the function remembers where it was created.

Official sources

Exercises

Was this page helpful?

One tap — no account needed.