Clean Code with ES6 Default Parameters & Property Shorthands

Share this article

Clean Code with ES6 Default Parameters & Property Shorthands
Creating a method also means writing an API — whether it’s for yourself, another developer on your team, or other developers using your project. Depending on the size, complexity, and purpose of your function, you have to think of default settings and the API of your input/output.
Default function parameters and property shorthands are two handy features of ES6 that can help you write your API.

ES6 Default Parameters

Let’s freshen up our knowledge quickly and take a look at the syntax again. Default parameters allow us to initialize functions with default values. A default is used when an argument is either omitted or undefined — meaning null is a valid value. A default parameter can be anything from a number to another function.
// Basic syntax
function multiply (a, b = 2) {
  return a * b;
}
multiply(5); // 10

// Default parameters are also available to later default parameters
function foo (num = 1, multi = multiply(num)) {
  return [num, multi];
}
foo(); // [1, 2]
foo(6); // [6, 12]

A real-world example

Let’s take a basic function and demonstrate how default parameters can speed up your development and make the code better organized. Our example method is called createElement(). It takes a few configuration arguments, and returns an HTML element. The API looks like this:
// We want a <p> element, with some text content and two classes attached.
// Returns <p class="very-special-text super-big">Such unique text</p>
createElement('p', {
  content: 'Such unique text',
  classNames: ['very-special-text', 'super-big']
});

// To make this method even more useful, it should always return a default
// element when any argument is left out or none are passed at all.
createElement(); // <div class="module-text default">Very default</div>
The implementation of this won’t have much logic, but can become quite large due to it’s default coverage.
// Without default parameters it looks quite bloated and unnecessary large.
function createElement (tag, config) {
  tag = tag || 'div';
  config = config || {};

  const element = document.createElement(tag);
  const content = config.content || 'Very default';
  const text = document.createTextNode(content);
  let classNames = config.classNames;

  if (classNames === undefined) {
    classNames = ['module-text', 'default'];
  }

  element.classList.add(...classNames);
  element.appendChild(text);

  return element;
}
So far, so good. What’s happening here? We’re doing the following:
  1. setting default values for both our parameters tag and config, in case they aren’t passed (note that some linters don’t like parameter reassigning)
  2. creating constants with the actual content (and default values)
  3. checking if classNames is defined, and assigning a default array if not
  4. creating and modifying the element before we return it.
Now let’s take this function and optimize it to be cleaner, faster to write, and so that it’s more obvious what its purpose is:
// Default all the things
function createElement (tag = 'div', {
  content = 'Very default',
  classNames = ['module-text', 'special']
} = {}) {
  const element = document.createElement(tag);
  const text = document.createTextNode(content);

  element.classList.add(...classNames);
  element.appendChild(text);

  return element;
}
We didn’t touch the function’s logic, but removed all default handling from the function body. The function signature now contains all defaults. Let me further explain one part, which might be slightly confusing:
// What exactly happens here?
function createElement ({
  content = 'Very default',
  classNames = ['module-text', 'special']
} = {}) {
  // function body
}
We not only declare a default object parameter, but also default object properties. This makes it more obvious what the default configuration is supposed to look like, rather than only declaring a default object (e.g. config = {}) and later setting default properties. It might take some additional time to get used to it, but in the end it improves your workflow. Of course, we could still argue with larger configurations that it might create more overhead and it’d be simpler to just keep the default handling inside of the function body.

ES6 Property Shorthands

If a method accepts large configuration objects as an argument, your code can become quite large. It’s common to prepare some variables and add them to said object. Property shorthands are syntactic sugar to make this step shorter and more readable:
const a = 'foo', b = 42, c = function () {};

// Previously we would use these constants like this.
const alphabet = {
  a: a,
  b: b,
  c: c
};

// But with the new shorthand we can actually do this now,
// which is equivalent to the above.
const alphabet = { a, b, c };

Shorten Your API

Okay, back to another, more common example. The following function takes some data, mutates it and calls another method:
function updateSomething (data = {}) {
  const target = data.target;
  const veryLongProperty = data.veryLongProperty;
  let willChange = data.willChange;

  if (willChange === 'unwantedValue') {
    willChange = 'wayBetter';
  }

  // Do more.

  useDataSomewhereElse({
    target: target,
    property: veryLongProperty,
    willChange: willChange,
    // .. more
  });
}
It often happens that we name variables and object property names the same. Using the property shorthand, combined with destructuring, we actually can shorten our code quite a bit:
function updateSomething (data = {}) {
  // Here we use destructuring to store the constants from the data object.
  const { target, veryLongProperty: property } = data;
  let { willChange } = data;

  if (willChange === 'unwantedValue') {
    willChange = 'wayBetter';
  }

  // Do more.

  useDataSomewhereElse({ target, property, willChange });
}
Again, this might take a while to get used to. In the end, it’s one of those new features in JavaScript which helped me write code faster and work with cleaner function bodies. But wait, there’s more! Property shorthands can also be applied to method definitions inside an object:
// Instead of writing the function keyword everytime,
const module = {
  foo: 42,
  bar: function (value) {
    // do something
  }
};

// we can just omit it and have shorter declarations
const module = {
  foo: 42,
  bar (value) {
    // do something
  }
};

Conclusion

Default parameters and property shorthands are a great way to make your methods more organized, and in some cases even shorter. Overall, default function parameters helped me to focus more on the actual purpose of the method without the distraction of lots of default preparations and if statements. Property shorthands are indeed more of a cosmetic feature, but I found myself being more productive and spending less time writing all the variables, configuration objects, and function keywords. Do you already use default parameters and property shorthands? This article was peer reviewed by Sebastian Seitz. Thanks to all of SitePoint’s peer reviewers for making SitePoint content the best it can be!

Frequently Asked Questions (FAQs) about ES6 Default Parameters

What are the benefits of using ES6 default parameters in JavaScript?

ES6 default parameters offer several benefits. Firstly, they help in making your code cleaner and more readable. Instead of having to check if a parameter is undefined and then assigning a default value, you can do it all in one line. This reduces the amount of code you have to write and makes it easier for others to understand your code. Secondly, they help in preventing errors. If a function expects a certain parameter and it’s not provided, it could lead to unexpected results or errors. By setting default parameters, you ensure that your function has all the parameters it needs to work correctly.

Can I use ES6 default parameters with destructuring assignment?

Yes, you can use ES6 default parameters with destructuring assignment. This is a powerful feature of ES6 that allows you to unpack values from arrays or properties from objects into distinct variables. When combined with default parameters, you can extract values from an object or array and assign default values if the extracted value is undefined.

How does the ES6 default parameters feature differ from the arguments object in JavaScript?

The arguments object is an array-like object that contains all of the arguments passed to a function. However, it does not have all the methods of an array and it is not as flexible as the ES6 default parameters feature. With default parameters, you can set default values for any parameters that are undefined, which is not possible with the arguments object.

Can I use ES6 default parameters in constructor functions?

Yes, you can use ES6 default parameters in constructor functions. This can be particularly useful when creating new instances of a class. If certain parameters are not provided when creating the new instance, the default parameters will be used, ensuring that the new object has all the necessary properties.

Are there any performance implications when using ES6 default parameters?

In general, the performance impact of using ES6 default parameters is minimal and should not be a concern. However, like any feature, it should be used judiciously. Overuse of default parameters, especially in performance-critical code, could potentially lead to slower execution times. As always, it’s important to test your code and monitor its performance.

Can I use ES6 default parameters with arrow functions?

Yes, you can use ES6 default parameters with arrow functions. Arrow functions, introduced in ES6, provide a concise syntax to write function expressions. They are particularly useful when working with higher-order functions that take other functions as arguments.

How does the ES6 default parameters feature handle null values?

If a parameter is passed with a null value, the ES6 default parameters feature will not assign the default value. This is because null is considered a value in JavaScript, unlike undefined. If you want to assign a default value when a parameter is null, you will need to handle this case separately in your code.

Can I use ES6 default parameters in recursive functions?

Yes, you can use ES6 default parameters in recursive functions. This can be particularly useful when you want to provide a base case for your recursive function but don’t want to require the caller to always provide it.

Can I use ES6 default parameters with rest parameters?

Yes, you can use ES6 default parameters with rest parameters. However, keep in mind that the rest parameter must be the last parameter in your function definition. Also, you cannot assign a default value to the rest parameter itself, but you can assign default values to the individual parameters that are part of the rest parameter.

Can I use ES6 default parameters with the spread operator?

Yes, you can use ES6 default parameters with the spread operator. The spread operator allows you to expand an iterable, like an array, into individual elements. When combined with default parameters, you can pass an array of values to a function and assign default values to any parameters that are undefined.

Moritz KrögerMoritz Kröger
View Author

Moritz is a German front-end developer living in Berlin. Although Germans typically have a thing for extra long compound words, he's a friend of short functions.

ES2015es6JS Quick Tipslearn-modernjsmodernjsmodernjs-hubvanilla javascript
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week