Jul 14, 2020 • By Jake Dohm
Refactoring Your Function Parameters
In this lesson, we take a function and refactor it to make both the function definition, and the way we call the function more readable.
In this video we're going to look at how to clean up our function definitions and the way that we call functions by using named parameters and setting defaults for our optional parameters.
For this example we have a function called renderlist which takes the list to render, whether that list should be ordered or unordered, the color that the item should be rendered in, and the background color for the list.
Inside of that function all we're doing is checking if some of these optional parameters like ordered color and background color are defined and if not we're giving them a value right here in the... but we're actually doing this in the body of the function.
So we're going to look at how to refactor some of this. The way that we would call this function is by passing an array as the first parameter, this is our list, and then true or false for this ordered, and then we could pass a hex code here for color and a hex code for background color.
The first thing that I noticed though is that we're passing in undefined, which seems weird because undefined is the base value for if you don't pass in a parameter, but the problem is that because we're passing in an ordered list of parameters instead of a named list because we want to pass in background color we have to pass something for color so that we can pass this last thing.
So let's go ahead and refactor this function to accept named parameters so that we don't have to pass in undefined for any optional parameters.
We're going to go ahead and come up here and we're going to refactor this to accept an object of parameters and we're actually going to destructure these values directly from that object. So we're gonna add some g-structuring right here and so we're gonna destructure list ordered color and background color and then when we call the function we will call it with list and then ordered set ordered to true. We don't need to pass undefined because this is not an ordered parameter, these are names, so it doesn't matter that if we don't pass in color it'll automatically be set to undefined and we'll pass in background color as that hex value.
Okay, perfect, so you can see this is already a little bit more readable even in the way we call the function because you can see what we're passing in. Before we were just passing in true as a value but you couldn't tell without looking at the function, going back to the function definition, or with some good dev tools that what exactly that boolean value of true or false was doing. You also couldn't tell what this value hex value was doing unless you looked at the function definition. But now this allows us to see directly from our function call exactly what's going to happen. You know you can tell from here you're going to get a list, it's going to be ordered, and it's going to have a background color which is whatever we pass in here.
We've done our first thing: we've named our parameters but now one problem is that if we want to call this in the most basic form, which should be something like this, you know renderlist and pass it an array, we can't do that anymore because we still need to pass in an object with a key of lists and a value of our list. This is a little bit more clunky than how we were previously able to do it which was like this... just calling renderlist directly. So, for the most basic usage of the function we've actually made it more complicated. Well, for a more complicated usage we've actually made it clearer.
But I don't really want to make that trade off. I really want the best of both worlds. So what we're going to do is we're going to make list a separate parameter so our first parameter will be the list and then the second parameter will be our options that are optional and you can pass these in when you're calling the function and you want to change something about the default way that it's called. So, if you just call it with the list it'll set order to true, it'll set these colors to their defaults, and you'll be good to go. So with that change we can now come down here and we can pass it just like this: we'll pass in our list, and then we'll pass an object with options, which is still very readable renderlist, and then you give it the list. That's very clear what's happening and then you can optionally pass an object full of options that will kind of change how that list is rendered.
Okay, so if you look in the browser you'll see that it says cannot destructure property ordered of undefined... so we have our order here and it's trying to destructure that but when we call renderlist like this what it really reads is, you know, passing in our function and then it passes undefined for the second parameter automatically because we didn't pass anything, and then what our function body is trying to do is pretty much this: const ordered and then the other things equals our second param which is undefined. So, it's trying to destructure something from undefined which doesn't work. So what we need to do is we need to set a default parameter for our second param up here so we could. It kind of makes sense to show it like this. You say options and then you set options to an empty object and then this down here would be like options.ordered but because we still want to do that destructuring what we can do is we can actually put that right back in where it was.
So we say destructure ordered color and background color from our second parameter and if the second parameter isn't defined, like when we call it right here with only one parameter and one argument then set it to an empty object. And this will allow it to because you can destructure from an empty object, you can't destructure from undefined, so if I refresh you'll see that we cleared up that error and we can call renderlist just like that and that works just fine even though we're not passing that second parameter.
Okay, so this gives us two really clean ways to call our function and this is pretty much as good as our function call is going to get. But one thing that we don't have yet is we still have this weird default setting in our function body which doesn't really make a lot of sense. It's kind of writing imperative code for something that should be declarative. You should be able to declare what the default for each parameter is. So we can actually move each of these things up into our destructuring. So we can say ordered equals true and what this will do is it'll set order to the value that's passed in, like here, true or it'll set it to fall back to whatever value we give it. So we'll set order to be false by default because we're passing true, and then we'll set the background color to be... or the color, to be this hex value and we'll set the background color to be transparent by default and then we can get rid of all of this checking, which is just checking if it's undefined, and this will do the exact same thing we were just doing, but it will do it in a declarative way. Kind of clean that up so you can kind of see. So we take our list and then we take an object of params which is ordered color and background color and we set fallbacks for each of those. And you can come back here and we can try to run this and you'll see that doesn't give us any errors, and it does if we kind of console.log, we'll just console.log list, ordered color, background color, every time this function is called.
When the console logs that out for the first renderlist we're only passing the list so we see the list is one, two, and then it uses all the defaults we have: transparent, our color, which is our default color and then order is false.
The second time that we call it we call it and we tell it order to be true and we give it a background color and you'll see that that's reflected and what's console logged out here.
That's pretty much it. that's all you need to know, um, Whenever I see a function call that looks kind of vague, something like our initial renderlist, where you're passing it maybe a list and maybe a true, if you see an undefined in there, to kind of get you to a third value, that's when you might want to reach for named parameters. You might want to reach for... anytime you're doing imperative checking of undefined in your function body you might want to reach for optional parameters and setting default for those parameters.