ECMAScript 6 (ES6) brings many new features. One of the features I'm most existed about is destructuring.

In a nutshell this allows you to extract values from an object by describing the object's layout rather than accessing elements within it. This will become very important later as the examples get more complicated.

Disclaimer: ES6 is not fully supported by all browsers yet so most people will have to use a JavaScript compiler to convert the new ES6 syntax down to ES5 so that it will work on most browsers. I recommend Babel. Now that's out of the way...

Let's start off with some ES5 (the currently supported JavaScript):

function displayPerson(person) {
var description = person.name;
if (typeof person.dateOfBirth !== 'undefined') {
description += " was born on " + person.dateOfBirth;
}
console.log(description);
}

displayPerson({name: 'Bob Smith'});
// Bob Smith

displayPerson({name: 'Joe Bloggs', dateOfBirth: '7/6/1985'});
// Joe Bloggs was born on 7/6/1985

Seems simple enough. However, there's a one big problem. The caller has to examine displayPerson to understand what properties are required and optional. It also doesn't display any other properties that may be valid but just not used yet. We could use a comment block above to document the individual properties, but thats a hassle and may still require the caller to goto the file and look at the function.

Now let's see how this could be handled in ES6:

function displayPerson({name: name, dateOfBirth: dateOfBirth}) {
let description = name;
if (typeof dateOfBirth !== 'undefined') {
description += " was born on " + dateOfBirth;
}
console.log(description);
}

All we've done is allow the name and dateOfBirth to be assigned to a variable of the same name based on the structure of the incoming object. Since they are the same name we can make use of another ES6 feature. When object property names are the same name as the variable they can be collapsed:

function displayPerson({name, dateOfBirth}) {

This looks neater. But we can also use default values to indicate that the dateOfBirth is optional:

function displayPerson({name, dateOfBirth = undefined}) {

This may seem redundant since dateOfBirth will be undefined if not provided anyway. But you could use a different default value or expression. I like to use the default value to explicitly state that it is optional.

A More Complex Example

Let's extend this to something more complicated and practical like processing a nested object:

function displayPerson({name, address: {street, postcode}}) {
console.log(name + " lives at " + street);
}

displayPerson({name: 'John', address: {street: 'Ramsay St', postcode: 1234}});
// John lives at Ramsay St

It would be safe to assume as the caller that all of the variables are required. If address is optional we get into real trouble now:

displayPerson({name: 'John'})
// undefined is not an object

We can make address optional by assigning an empty object:

function displayPerson({name, address: {street, postcode} = {}}) {
console.log(name + " lives at " + street);
}

displayPerson({name: 'John'})
// John lives at undefined

It prevents an attribute from being undefined in the when extracted from the object. We would probably still need custom error handling code when things are missing.

Enforcing Required Values

Some people would call this a hack, but not at all. The default values (or expressions in this case) are only evaluated if the property doesn't exist. We can use this logic in our favour:

function required(field) {
throw new Error(field + ' is required!');
}

function displayPerson({
name = required('name'),
address: {
street = required('street'),
postcode
} = {}
}) {
// We know name and street must be defined.
console.log(name + " lives at " + street);
}

Self-documenting APIs

Heres an example response of the three most recent trades from independentreserve.com:

{
"Trades":[
{
"TradeTimestampUtc":"2016-01-10T03:26:00.1995957Z",
"PrimaryCurrencyAmount":0.30051550,
"SecondaryCurrencyTradePrice":449.02
}, {
"TradeTimestampUtc":"2016-01-10T03:22:20.9286286Z",
"PrimaryCurrencyAmount":0.30138850,
"SecondaryCurrencyTradePrice":450.16
}, {
"TradeTimestampUtc":"2016-01-10T03:09:35.2613933Z",
"PrimaryCurrencyAmount":0.30137260,
"SecondaryCurrencyTradePrice":448.91
}
],
"PrimaryCurrencyCode":"Xbt",
"SecondaryCurrencyCode":"Usd",
"CreatedTimestampUtc":"2016-01-10T03:29:23.4256336Z"
}

It's very possible that if we write some code to process these we will not need all the data available. However, without pasting an example response in a comment above the code we would have no idea what fields are available to us or what format they are in without making the call again.

This is especially annoying for unit testing where we should be mocking these out and only need to see what the response format is without needing to make a request.

function example(value) {
return undefined;
}

function processRecentTrades({
Trades = example([]),
PrimaryCurrencyCode = example('Xbt'),
SecondaryCurrencyCode = example('Usd'),
CreatedTimestampUtc = example('2016-01-10T03:29:23.4256336Z')
}) {
$.each(Trades, (k, v) => processTrade(v));
}

function processTrade({
TradeTimestampUtc = example('2016-01-10T03:26:00.1995957Z'),
PrimaryCurrencyAmount = example(0.30051550),
SecondaryCurrencyTradePrice = example(449.02)
}) {
// ...
}