EduFlow
JavaScript Fundamentals
0%

Section 2 · Logic and Functions

Functions: Declarations, Arrows and Defaults

19 min4 min readCode playground

Lesson at a glance

Write your own functions as declarations and arrow functions, pass arguments in and get results out with return, give parameters default values, and pass functions to other functions.

  1. 1Declaring and calling a function
  2. 2Default parameters
  3. 3Arrow functions
  4. 4Functions are values
  5. 5Small, pure functions

No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.

In the last two lessons you filled in function bodies that were written for you. Now you write your own. A function is a named, reusable piece of a program: you write the steps once and run them whenever you need, with different inputs. Pocket formats money in a dozen places; without functions you would copy (cents / 100).toFixed(2) into every one, and fix every copy when the format changes.

Declaring and calling a function

JavaScript
function formatMoney(cents) {
  const dollars = (cents / 100).toFixed(2);
  return `${dollars}`;
}

console.log(formatMoney(1220));
console.log(formatMoney(450));

The first five lines are a function declaration. They do not run anything; they create a function named formatMoney and remember its steps. cents is a parameter, a name for an input that does not have a value yet.

formatMoney(1220) is a call. The value in the parentheses, 1220, is an argument. When the engine reaches the call, it pauses the current line, jumps into the function with cents pointing at 1220, runs the body, and comes back when it hits return. The call expression is then replaced by the returned value, "$12.20", which console.log prints.

The call formatMoney(1220) passes 1220 into the parameter cents. The function body runs and returns the string $12.20, which replaces the call in the original line. formatMoney(1220) function formatMoney cents = 1220 dollars = "12.20" return "$12.20" argument return value
A call sends arguments in and gets the return value back

A function can have several parameters, separated by commas, and the arguments are matched by position: the first argument goes to the first parameter, and so on.

return does two things: it decides the result, and it ends the function on the spot. Any line after a return in the same block never runs. If a function finishes without reaching a return, the call evaluates to undefined.

Default parameters

If you call a function with fewer arguments than parameters, the missing ones are undefined. A default parameter gives them a sensible value instead:

JavaScript
function formatMoney(cents, symbol = "$") {
  return `${symbol}${(cents / 100).toFixed(2)}`;
}

console.log(formatMoney(1220));
console.log(formatMoney(1220, "€"));

The default is used when the argument is missing or undefined, and only then. Passing 0, "" or null counts as a real argument.

Arrow functions

There is a second, shorter way to write functions, the arrow function. It is a value, so you store it in a const:

JavaScript
const toCents = (dollars) => Math.round(dollars * 100);
const isBig = (cents) => cents >= 10000;

console.log(toCents(12.2), isBig(toCents(120)));

When the body is a single expression, as here, you leave out the braces and the return: the expression’s value is returned automatically. When you need several statements, use braces, and then return is required again:

JavaScript
const budgetLeft = (budget, spent) => {
  const left = budget - spent;
  return left > 0 ? left : 0;
};
console.log(budgetLeft(2000, 2200));

Which style should you use? Both are everywhere in real code. A common default, and the one this course follows: declarations for named, top-level functions, arrows for short functions passed to other functions. One practical difference: declarations are hoisted, which means you can call them on a line above where they are written. A const arrow function only exists once its line has run.

Functions are values

In JavaScript a function is a value like a number or a string. You can store it, and you can pass it to another function as an argument. That is the idea behind much of modern JavaScript:

JavaScript
function applyToAll(amounts, transform) {
  const results = [];
  for (const amount of amounts) {
    results.push(transform(amount));
  }
  return results;
}

const formatMoney = (cents) => `${(cents / 100).toFixed(2)}`;
console.log(applyToAll([450, 1220], formatMoney));
console.log(applyToAll([450, 1220], (c) => c * 2));

applyToAll does not know or care what transform does; it calls it once per item and collects the results with push, which adds an item to the end of an array. A function passed in like this is called a callback. Notice that you pass formatMoney without parentheses: you are handing over the function, not calling it. Arrays have this exact helper built in, called map, and section 3 puts it to work.

Small, pure functions

Notice what every helper in this lesson has in common: it uses only its parameters, returns a result, and changes nothing outside itself. A function like that is called pure. Give it the same arguments and it returns the same answer every time, so you can test it with one line, reuse it anywhere, and trust it without reading its body again.

Not every function can be pure. Something eventually has to print to the screen or save data. The habit that keeps programs manageable is to do the calculating in small pure functions and keep the printing and saving in a few clearly named places. Pocket follows that split all the way to the final app.

Functions create their own little world of names inside them. How that world relates to the code around it is called scope, and it is the subject of the next lesson.

Key takeaways

  • A function packages steps under a name; parameters are the inputs it declares, arguments are the values you pass when you call it.
  • return ends the function and hands a value back; a function without return gives back undefined.
  • Arrow functions ((x) => x * 2) are a shorter syntax; with curly braces they need an explicit return.
  • Default parameters (symbol = \"$\") apply when an argument is missing or undefined.
  • Functions are values, so you can store them in variables and pass them to other functions.

Further reading

Check your understanding

4 questions

Question 1 of 4

What does this log?

JavaScript
const double = (n) => {
  n * 2;
};
console.log(double(4));
Question 2 of 4

function formatMoney(cents, symbol = "

quot;) { … } is called as formatMoney(450, undefined). What is symbol inside?

Question 3 of 4

Which line calls isBig from before its definition without an error?

Question 4 of 4

const amounts = [450, 1220]; and function toDollars(c) { return c / 100; }. What does amounts.map(toDollars) need from you?

Practice

Code playground

Pocket's money helpers

Write four small functions Pocket will use from now on:

  1. toCents(dollars) returns the amount in whole cents (4.1 gives 410).
  2. formatMoney(cents, symbol) returns a string like "$12.20". symbol defaults to "
    quot;
    .
  3. isBig, an arrow function that returns true for 10000 cents or more.
  4. countWhere(amounts, test) returns how many items in amounts make the callback test(amount) return a truthy value.
// 1. Dollars (like 4.1) to whole cents (410)
function toCents(dollars) {
}

// 2. Cents to a display string, with a symbol that defaults to "
quot; function formatMoney(cents) { } // 3. Replace null with an arrow function: true for 10000 cents or more const isBig = null; // 4. Count the amounts for which test(amount) returns true function countWhere(amounts, test) { return 0; } console.log(formatMoney(toCents(12.2)));
Loading the editor…

Ctrl/⌘ + Enter to run · Runs in a sandbox in your browser. Nothing leaves your device.

Console

(no output)

Checks

  • toCents returns whole cents
  • formatMoney returns strings like “$12.20”
  • formatMoney uses a custom symbol and defaults to “$”
  • isBig is an arrow function with the 10000-cent threshold
  • countWhere counts items that pass the callback