Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Introducing ES2015 The Cooler Parts of ES2015 Destructuring

Destructuring functions

I'm confused about this part of the lesson.

function getData({ url, method = 'post' } = {}, callback) {
  callback(url, method);
}

getData({ url: 'myposturl.com' }, function (url, method) {
  console.log(url, method);
});

Which part of this code is the "destructered" part? i.e. What would it look like if it weren't destructered?

Also, why is there an empty set of brackets within the list of parameters here?:

function getData({ url, method = 'post' } = {}, callback) {
  callback(url, method);
}

What does it mean? It wasn't explained in the video:

3 Answers

akak
akak
29,445 Points

The empty brackets there is the part of the syntax to allow deconstruction of an object. Look closely how the getData function is being called. It get's only two arguments: an object with url key, and a callback function.

Based on that fact, without using deconstructing (and just to stay ES5 all the way also with the old way of supplying default arguments) this function would look like this:

function getData(data, callback) {
  data.method = data.method || 'post';
  callback(data.url, data.method);
}

But since we know data will be an object with keys url and method we can destructure it using {url, method} = {}. And now access directly url and method keys without doing data.url, data.method.

EDIT: As correctly pointed out by Tom Geraghty in the comments, the = {} part is not required in deconstructing. It's only a safeguard that provides {} as the default value if the function is called with the first argument as undefined. It's totally optional, and the deconstruction will work fine as described without it as well.

Got it, thanks very much!

Tom Geraghty
Tom Geraghty
24,174 Points

The highest voted answer doesn't seem correct. The ={} is setting the default values as OPTIONAL for the function to be called. So you can call the function like this:

getData({}, callback);

or this:

getData({url: things, method: stuff}, callback);

Without the ={} in the parameter, if you called it the first way getData({}, callback) you would get an error.

Read the linked article by Loris Guerra here especially:

The way to circumvent this function call error is to set a default value for the configuration object itself:*

function myFunc({name = 'Default user', age = 'N/A'} = {}) {
}

*Emphasis mine

Ken S.
Ken S.
3,838 Points

Hi Tom,

Your effort to explain this for us is appreciated, however it seems there is little point to adding the default value of an empty object here.

When the function is called in the way you suggest: getData({}, callback);

The function does NOT fail even with the default value removed, because you are providing the exact same argument as would have been default, so even if the default is missing from the function, you are still running the function using the exact same arguments.

Thats why this seems pointless to me in this example and even more confusing because it is not explained in the video. The only way this seems to do anything is if you called getData in this way:

getData(undefined, callback);

But if you are going to call it in this way, you might as well type the {} in place of the undefined and get the exact same thing. I understand if the first argument is the only argument in a function, but otherwise it just seems completely pointless to me. Can an experienced dev chime in and settle this once and for all?

akak
akak
29,445 Points

Ken,

Tom is right with the explanation of how this works. And you are also right that the only case that would get handy is when you call the function like getData(undefined, callback). But this is a more common case than one might expect. This is a very basic example to illustrate this:

const users = [
  {name: 'Mark', age: 22, active: false},
  {name: 'Karen', age: 21, active: true},
  {name: 'Andy', age: 30, active: true}
]

function getActiveUsersDetails({name, age, active} = {}, callback) {
  if (!name) {
    callback('No such user', null);
  } else if (!active) {
    callback('User is inactive', null);
  } else {
    callback(null, {name, age})
  }
}

function getUser(name) {
  const user = users.find(user => user.name === name);

  getActiveUsersDetails(user, (error, data) => {
    if (error) {
      console.warn(error);
    } else {
      console.log(`User ${user.name} is active. Her/his age is ${user.age}`)
    }
  });  
}


getUser('Mark');
getUser('Karen');
getUser('a_guy_thats_not_on_the_list'); 

Array.find returns either element or undefined. So in case when it returns undefined the first parameter to our function would be... wel undefined :) If you remove ={} in the getActiveUsersDetails the third call to the function to get a_guy_thats_not_on_the_list would fail with TypeError.

You could, of course, do a guard in getUser function like:

if (user) {
   getActiveUsersDetails(user);
} else {
  console.warn('No such user');
}

so getActiveUsersDetails would not be called with undefined. But it all depends on your implementation and when do you want this check to happen. I think it's a good idea to guard the getActiveUsersDetails function with default ={} so it never crashes with TypeError. Since you might be reusing it a lot in different places and writing each time a guard might be not the best solution.

Here's jsBin if you want to play with this a bit yourself.

Hope this helps and clears things a bit. Cheers!

Ken S.
Ken S.
3,838 Points

akak,

Its helpful! Thank you!