ES2015 Part 5: Destructuring

Part 5 in the series of ES2015 deals with destructuring: with arrays and with objects.

Array destructuring

The following logCoordinate function takes an array as a parameter, and then reads the values from three indexes and assigns them to variables:

1    function logCoordinate(coordinate) {
2        var x = coordinate[1];
3        var y = coordinate[2];
4        var z = coordinate[3];
5        return "Your spacial coordinate is (" + x + ", " + y + ", " + z + ")";
6    }
7
8    logCoordinate(["5-October-2016", 12, 35, 22]);

Here the logCoordinate function gets called with an array containing four items:

  • A string that represents a calendar date
  • The location’s x coordinate
  • The location’s y coordinate
  • The location’s z coordinate

The ES2015 destructuring syntax can be used to make these assignments all in one line. On the left hand side of the variable declaration is the list of variable names enclosed in square brackets. On the right hand side is the array that contains the values to be assigned.

1    function logCoordinate(coordinate) {
2        let [date, x, y, z] = coordinate;
3        return "Your spacial coordinate is (" + x + ", " + y + ", " + z + ")";
4    }
5
6    logCoordinate(["5-October-2016", 12, 35, 22]);

Note: in this example, we do not need the first array element (the date string). In that case, the array destructuring can omit the date variable name. It is still necessary to have a comma before the x variable, to ensure the correct positional value assignment.

Here’s how that looks like:

1    function logCoordinate(coordinate) {
2        let [, x, y, z] = coordinate;
3        return "Your spacial coordinate is (" + x + ", " + y + ", " + z + ")";
4    }
5
6    logCoordinate(["5-October-2016", 12, 35, 22]);

Object destructuring

Similar to array destructuring, in ES2015, parts of an object can be assigned to variables.

To illustrate, let’s work with an object. In this example, it’s an object that represents the key features of a movie:

1    var JAWS = {
2        title: "Jaws",
3        year: 1975,
4        people: {
5            director: "Steven Spielberg",
6            star: "Roy Scheider"
7        }
8    };

The following function gets called with the JAWS object:

1    function movieInfo(movie) {
2        let title = movie.title;
3        let year = movie.year;
4        let director = movie.people.director;
5        let star = movie.people.star;
6        return title + ' played in ' + year + ' directed by ' + director + ' starring ' + star;
7    }
8
9    movieInfo(JAWS);

The call to movieInfo returns the following string:

1    Jaws played in 1975 directed by Steven Spielberg starring Roy Scheider

Using ES2012’s object destructuring, the variable declaration on the left hand side of the = sign, look like an object declaration with key/value pairs separated by : characters inside curly braces:

1    function movieInfo(movie) {
2        let {title: title, year: year} = movie;
3        let director = movie.people.director;
4        let star = movie.people.star;
5        return title + ' played in ' + year + ' directed by ' + director + ' starring ' + star;
6    }
7
8    movieInfo(JAWS);

The first line inside the function uses ES2015’s object destructuring to define two variables: title and year. The values for these variables correspond to the “title” and “year” attributes from the movie object. The variable name and the key/attribute from the object must not necessarily have the same name. In the above example, there’s a lot of repetition because the variable name is the same as the object key. In ES2015’s object destructuring, there’s a shortcut if the variable name and the object key is the same. The above example can be rewritten as follows:

1    function movieInfo(movie) {
2        let {title, year} = movie;
3        let director = movie.people.director;
4        let star = movie.people.star;
5        return title + ' played in ' + year + ' directed by ' + director + ' starring ' + star;
6    }
7
8    movieInfo(JAWS);

That’s syntax takes some getting used to, but it’s nice and concise. Note, that we still have separate assignment statements for director and star. Those are attributes of the nested object under the “people” attribute. Nested attributes can also be used in ES2015’s object destructuring, by specifying the nested object’s key and using another set of curly braces. Here’s another that assigns all four variables in one object destructuring line:

1    function movieInfo(movie) {
2        let {title, year, people: {director, star}} = movie;
3        return title + ' played in ' + year + ' directed by ' + director + ' starring ' + star;
4    }
5
6    movieInfo(JAWS);

That looks very concise!

The object destructuring can even appear in the parameter list. This way, the function receives four parameter values but they come from a single object passed in as an argument:

1    function movieInfo({title, year, people: {director, star}}) {
2        return title + ' played in ' + year + ' directed by ' + director + ' starring ' + star;
3    }
4
5    movieInfo(JAWS);

This is the shortest version so far, but it is questionable whether it is easier to understand. Better use the version that takes a single movie object parameter.

Finally, when destructuring objects, the source object (on the right hand side of the = sign) might not have the attributes specified on the left hand side of the = sign. In that case, it’s possible to supply a default value. Here’s an example that takes a SULLY movie object that’s missing the year attribute.

 1    var SULLY = {
 2        title: "Sully",
 3        people: {
 4            director: "Clint Eastwood",
 5            star: "Tom Hanks"
 6        }
 7    };
 8
 9    function movieInfo(movie) {
10        let {title, year = 2016, people: {director, star}} = movie;
11        return title + ' played in ' + year + ' directed by ' + director + ' starring ' + star;
12    }
13
14    movieInfo(SULLY);

Default parameter values

Last topic is the ability to specify default parameter values, even though it’s not directly related to destructuring. When using destructuring inside function parameter lists, one can use default values - that’s why this topic made it into “Part 3”.

In JavaScript, function parameters are optional. Even if the function declares two parameters, the function can still be called with zero, one or many parameters.

Let’s say we have a function that takes two parameters: an amount and a tax percentage and it returns the after-tax amount:

1    function totalAmount(amount, taxPercentage) {
2        return amount * (100 + taxPercentage) / 100;
3    }
4
5    totalAmount(25.00, 6);

Here we call the function with two arguments: the amount 25 and tax percentage of 6.

What if the tax does not apply? The tax percentage could be zero and it would be nice to let it default to zero if the second argument is not passed in. Here’s one way of achieving this, by checking if the parameter is undefined. Here we provide a default value of 0 if the parameter was not supplied:

1    function totalAmount(amount, taxPercentage) {
2        if (taxPercentage === undefined) {
3            taxPercentage = 0;
4        }
5        return amount * (100 + taxPercentage) / 100;
6    }
7    totalAmount(25.00);

In ES2015 the default value can be specified in the function’s parameter list directly:

1    function totalAmount(amount, taxPercentage = 0) {
2        return amount * (100 + taxPercentage) / 100;
3    }
4    totalAmount(25.00);

Nice!