Functions and scope

JavaScript Function Parameters

Learn how JavaScript function parameters work, including ES6 default values and the ES2018 trailing comma so you can rearrange parameters without bugs.

A function accepts zero or more parameters. The names in the definition are placeholders for the values the caller passes in.

const dosomething = () => {
  //do something
}

const dosomethingElse = foo => {
  //do something
}

const dosomethingElseAgain = (foo, bar) => {
  //do something
}

Starting with ES6/ES2015, you can give parameters default values:

const dosomething = (foo = 1, bar = 'hey') => {
  //do something
}

Callers can omit trailing arguments. Missing ones pick up the default:

dosomething(3)
dosomething()

ES2018 added a trailing comma after the last parameter. That sounds tiny, but it stops comma mistakes when you move parameters around:

const dosomething = (foo = 1, bar = 'hey',) => {
  //do something
}

dosomething(2, 'ho!')

You can also pass a trailing comma at the call site:

dosomething(2, 'ho!',)

If you already have the arguments in an array, spread them into the call with the spread operator:

const dosomething = (foo = 1, bar = 'hey') => {
  //do something
}
const args = [2, 'ho!']
dosomething(...args)

When a function takes many positional parameters, I forget the order fast. Object destructuring keeps names at the call site:

const dosomething = ({ foo = 1, bar = 'hey' }) => {
  //do something
  console.log(foo) // 2
  console.log(bar) // 'ho!'
}
const args = { foo: 2, bar: 'ho!' }
dosomething(args)

Defaults also work on regular function expressions:

const foo = function(index = 0, testing = true) { /* ... */ }
foo()

Here is the same idea on a named parameter:

const doSomething = (param1) => {

}

Add a default when the caller might omit it:

const doSomething = (param1 = 'test') => {

}

You can default several parameters at once:

const doSomething = (param1 = 'test', param2 = 'test2') => {

}

Sometimes you receive one options object instead of many positional arguments. Before destructuring, you wrote defensive checks:

const colorize = (options) => {
  if (!options) {
    options = {}
  }

  const color = ('color' in options) ? options.color : 'yellow'
  ...
}

Destructuring with defaults replaces that boilerplate:

const colorize = ({ color = 'yellow' }) => {
  ...
}

If the caller passes nothing, default the whole parameter to an empty object:

const spin = ({ color = 'yellow' } = {}) => {
  ...
}

Try calling colorize() with no arguments in the console. You should see it use 'yellow' without throwing.

When you are unsure whether a caller will pass an object, the = {} default on the destructuring pattern is the pattern I reach for first.

Default values apply when the argument is undefined, not when someone passes null. If null should mean “use the default”, normalize it inside the function body before you destructure.

Lesson completed