Functions and Parameters

Declarations versus expressions, default and rest parameters, and functions as values.

A function is a named piece of work you can run again. This lesson uses the let and const rules from let, const, and Scope.

Two ways to write the same function

A declaration starts with the function keyword. An expression builds a function and stores it in a const.

function label(show) {
  return show.title + " (" + show.year + ")";
}

const alsoLabel = function (show) {
  return show.title + " (" + show.year + ")";
};

const show = { title: "Severance", year: 2022 };

console.log("declaration:", label(show));
console.log("expression: ", alsoLabel(show));

Both print Severance (2022). The difference is when each name exists.

A shorter form, the arrow function, comes in Arrow Functions and this.

Hoisting

A declaration is set up before the rest of the file runs, so you can call it above the line that defines it. A function expression follows const: you cannot use the name until that line has run.

console.log("declaration:", double(4));

function double(n) {
  return n * 2;
}

try {
  console.log("expression:", triple(4));
} catch (error) {
  console.log("expression:", error.constructor.name + ":", error.message);
}

const triple = function (n) {
  return n * 3;
};

double works because the declaration was hoisted. triple throws, for the same reason a const cannot be read too early.

Template literals

A template literal sits in backticks. ${...} inside it runs an expression and drops in the result.

const show = { title: "Severance", year: 2022, rating: 8.7 };

const text =
  `${show.title} (${show.year}), rating ${show.rating}`;

console.log(text);

The log reads Severance (2022), rating 8.7. The rating is an expression inside the string, not extra + signs.

Default parameters

If a caller skips an argument, the parameter is undefined. A default fills that gap.

function headline(title, kind = "show") {
  return title + " (" + kind + ")";
}

console.log(headline("Severance"));
console.log(headline("The Bear", "series"));

The first call never passed kind, so it used "show". The second call passed "series", so the default was ignored.

Only undefined triggers a default. null or "" do not.

Rest parameters

...titles collects leftover arguments into a list.

function listTitles(first, ...rest) {
  console.log("first:", first);
  console.log("rest: ", rest);
}

listTitles("Severance", "Andor", "Shogun");

first is "Severance". rest is the other two titles. The ... parameter must be last.

Functions are values

You can pass a function into another function, just like a string or a number.

function label(show) {
  return show.title + " (" + show.year + ")";
}

function applyToShow(show, fn) {
  return fn(show);
}

const show = { title: "Severance", year: 2022 };

console.log(applyToShow(show, label));

applyToShow does not know what label does. It receives label and runs it. That is how later lessons will pass a function to map or to a click handler.

Why this matters in loops

A var counter is one variable shared by every turn of the loop. A let counter is a new variable each turn. The difference shows up when a function runs later.

const titles = ["Severance", "Andor", "Shogun"];

for (let i = 0; i < titles.length; i++) {
  setTimeout(function () {
    console.log("let:", i, titles[i]);
  }, 0);
}

for (var j = 0; j < titles.length; j++) {
  setTimeout(function () {
    console.log("var:", j, titles[j]);
  }, 0);
}

The let lines print each title. The var lines all print 3 and undefined. The loop finished before any of those functions ran, and titles[3] does not exist.

Common mistakes

  • Expecting a function expression to be hoisted. Only declarations are.
  • Using null to request a default. Only undefined triggers it.
  • Putting the rest parameter anywhere but last. That is a syntax error.

Exercise

describeShow should take a title, an optional kind that defaults to "show", and any extra genre names after that. Right now it ignores everything past the first argument.

Both calls should print:

Severance (show)
Andor (series), Drama,War
function describeShow(title) {
  return title;
}

console.log(describeShow("Severance"));
console.log(describeShow("Andor", "series", "Drama", "War"));