One of the most important books about programming and programming style is a book called Clean Code. In this book, there is a crucial tip that I always try to follow: The maximum number of function parameters should be 3, and you should always try to use 2 or less. I didn’t realize why this was important initially, but as I continued on my path of writing a ton of Javascript, it began to hit me.

Let’s say we define the following function and we have six potential param values.

const addToInventory = function(itemName, category, brokerName, sellingCost, initialCost, inStock) { // Some code goes here };

From the function definition side, this makes perfect sense as we’ll have variables for each param. The variables are named pretty well, and they will mean something in the function code. However, we run into the problem of clarity when executing the function and the issue of setting default parameters. Calling this function may look like this

addToInventory("Awesome Thing", "Toys", "Chester McChester", 12, 6, false);

If you’re like me then if you were to come back to this code later, you would be scratching your head as to what each of these values meant. What is “12” supposed to be? Who is “Chester McChester?” Why is there a random “false” passed in?

Now let’s say that some of these params were optional and we could call the function like this

addToInventory("Awesome Thing", "Toys");

Not too bad in terms of clarity… but what happens when you want to set the initial cost? Do you have to then set brokerName and the sellingCost? Or could you just do this

addToInventory("Awesome Thing", "Toys", undefined, undefined, 6);

As if setting param values with no context is confusing enough, tossing in random “undefineds” just adds an extra layer of “wtf is going on here?”

Wrap param values in an object!

Let’s refactor `addToInventory` and instead use an object to hold all of our params. I’m going to use destructuring to show how you can easily unpack values off of the params object. If you haven’t used destructuring, then I suggest you read about it at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring.

const addToInventory = function(params) { const {itemName, category, brokerName, sellingCost, initialCost, inStock} = params; // Some code goes here };

// Or you could you could destructure right

// in the function parameter declaration const addToInventory = function({itemName, category, brokerName, sellingCost, initialCost, inStock}) { // Some code goes here };

Now let’s see what calling this function would look like now.

const params = {

itemName: "Awesome Thing",

category: "Toys",

brokerName: "Chester McChester",

sellingCost: 12,

initialCost: 6,

inStock: false

}; addToInventory(params); // And with optional values const params = {

itemName: "Awesome Thing",

category: "Toys",

initialCost: 6

}; addToInventory(params);

Boom. Now when I come back to this code later, I’ll know roughly what each of these values means since the object key will be available to guide me. I’ll understand that “Awesome Thing” is the item name and not some other random value. We also don’t need to set the object values in any particular order, and we can skip optional values.

So next question then, what do you do about defaults?

Default Values in ES6

I used destructuring in the earlier example since it has an extra perk. Destructuring allows us to set defaults for each variable we extract from the params (you can read more about it at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Default_values_2).

Let’s see how we might set defaults using destructuring.

const addToInventory = function(params) { const {itemName = 'someName', brokerName, sellingCost, initialCost = 0, inStock = true} = params; // Some code goes here };

Using this technique, itemName would default to ‘someName’, initialCost would default to 0, and inStock would default to “true”.

Using destructuring defaults is excellent for objects, but we initially stated that objects aren’t necessary when using one or two parameters. What about setting defaults for when we are not using an object?

ES6 Default Params

I couldn’t write a post about params and not mention ES6 default params. If you are going to have more than three params, you should probably use an object. If not, then you should check out ES6 Default parameters.

In the past, Javascript programmers often had to set defaults like this

const myFunc1 = function(param1, param2) {

if(param1 === undefined) {

param1 = myDefault1;

}

if(param2 === undefined) {

param2 = myDefault2;

}

// Some code goes here

}; // Or the more concise and risky const myFunc2 = function(param1, param2) {

param1 = param1 || myDefault1;

param2 = param2 || myDefault2;

// Some code goes here

};

This often annoyed developers as other languages had easy ways to set default parameters. Luckily, ES6 added default parameters and you can now do this.

const myFunc = function(param1 = myDefault1, param2 = myDefault2) {

// Some code goes here

};

Default params help to get rid of tedious programming and helps to stay away from the dumpster fire regarding falsy values in Javascript.

Default Values in ES5

I wanted to add a quick section for those that are stuck supporting old browsers and can’t use Babel.

If you haven’t used Object.assign then I highly suggest you check it out. The official summary from MDN states.

The `Object.assign()` method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.

It is a subtle but powerful method in the sense that you can easily merge objects, make clones, and set object priority based off of the order of sources.

Let’s see what setting defaults might look like with our `addToInventory` function.

const addToInventory = function(params) {

params = Object.assign({

itemName: "",

category: "Other",

brokerName: "General",

sellingCost: 0,

initialCost: 0,

inStock: false

}, params);



const {itemName, category, brokerName, sellingCost, initialCost, inStock} = params; // Some code goes here };

Now the initial “target” is set with all of our desired default params, and the params object that is passed in overwrites the defaults as needed. If your defaults object lives outside of the function (like in a global config object), you could even set an empty object as the target and set the defaults as a source.

Note that the target will be mutated so you shouldn’t set global objects as the target parameter.

const addToInventory = function(params) {

params = Object.assign({}, myDefaults, params); const {itemName, category, brokerName, sellingCost, initialCost, inStock} = params; // Some code goes here };

But what if I want to use all defaults? One of the nifty things about Object.assign is that it will ignore undefined sources. Meaning that in the function above, the params object could be passed in as ‘undefined’ and Object.assign would still work just fine.

Summary

Basically, here is what you can do to clean up your function params and effectively set defaults

Keep the number of function parameters to 3 or less

If you need more than 3 param values, use an object

If you use an object and can use ES6, use Destructuring to set default values

If you use an object and cannot use ES6, use Object.assign to easily set default values

If you are not using an object as a param and can use ES6, use ES6 default parameters

If you are not using an object as a param and cannot use ES6, you just have to check if the value is undefined

Hope this helps!