Benefit of default parameters

Let's say we're working on a weather application and we have a basic helper function that converts degrees fahrenheit to degrees celsius:

Seems pretty simple. We just need to know the formula to convert fahrenheit to Celsius. So let's create a function called convertTemperature, which will accept a number, namely, degrees celsius, and it's going to return a number, degrees fahrenheit:

​ ​functionconvertTemperature(celsius) {
   // celsius to fahrenheit}

And the formula for converting from celsius is as follows:

function convertTemperature(celsius) {
  // celsius to fahrenheit
  const fahrenheit = celsius * 1.8 + 32;
  return fahrenheit;
}

So we'll store the result of this operation in a variable called fahrenheit and then return it:

function convertTemperature(celsius) {
  // celsius to fahrenheit
  const fahrenheit = celsius * 1.8 + 32;
  return fahrenheit;
}

So let's try to this out. Let's say we want to convert 20 degrees celsius to fahrenheit. So we pass that into our function

convertTemperature(20);

[Run code] And we get 68

And let's try 21:

convertTemperature(21);

[Run code] We get this really long decimal.

So this is a bit of a problem, especially if we are displaying this number in the browser, we want to specify to how many decimal places the number should be. So let's control that with another argument called decimalPlaces:

function convertTemperature(celsius, decimalPlaces) {
  // celsius to fahrenheit
  const fahrenheit = celsius * 1.8 + 32;
  return fahrenheit;
}

And the way that we can cut off the result to so many decimal places is with a string method called toFixed, and we pass in the number of decimal places of precision as an argument:

​ ​functionconvertTemperature(celsius, decimalPlaces) {
   // celsius to fahrenheit
​ ​  const fahrenheit = (celsius * 1.8) + 32;
  // round result
   return fahrenheit.toFixed(decimalPlaces);}

And a small note is that toFixed returns a string, so if we want it to return a number, we can use the number function to perform an explicit type conversion like so:

​ ​functionconvertTemperature(celsius, decimalPlaces) {
   // celsius to fahrenheit
​ ​  const fahrenheit = (celsius * 1.8) + 32;
  // round result
   return Number(fahrenheit.toFixed(decimalPlaces));}

So now let's try this out and see if our error is fixed. We'll call this function again, providing 1 as the number of decimal places.

convertTemperature(21, 1);

[Run code] So great. This seems to have fixed our error.

However, what if we've used this function many times around our app and we haven't added this second argument?

Let's try calling our function without the decimalPlaces:

convertTemperature(21);

We get the wrong answer. We get 70 instead of 69.8 something.

So what do we do here?

Well, now if in most cases we want round to a certain number of decimal places, we can make that a default value within the function. How do we do that? We can add a conditional.

We could use an if-statement and say if there is no decimalPlaces argument provided, set decimalPlaces by default to 1

​ ​functionconvertTemperature(celsius, decimalPlaces) {
   // celsius to fahrenheit
   if (!decimalPlaces) {
     decimalPlaces = 1;
   }
​ ​  const fahrenheit = (celsius * 1.8) + 32;
  // round result
   return Number(fahrenheit.toFixed(decimalPlaces));}

But based off of what we've already learned about short circuiting, what can we do to shorten this code right here? Take a minute and see if you can improve this code...

We can use the or conditional to simply say, if decimalPlaces is a falsy value (and an argument that is not provided is always undefined), we can set it's default value to 1, like so

functionconvertTemperature(celsius, decimalPlaces) {
   // celsius to fahrenheit
  decimalPlaces = decimalPlaces || 1;
​ ​  const fahrenheit = (celsius * 1.8) + 32;
  // round result
   return Number(fahrenheit.toFixed(decimalPlaces));}

So now if we try executing convertTemperature without a second argument, as before:

convertTemperature(21);

We get the right answer, fixed to one decimal place, 69.8.

So everything looks fine up until this point, but there is a small problem with this approach. See if you can spot it. What happens, for example, if we don't want any decimal places. What if we just want a whole number, an integer?...

If we want an integer, we would have to provide 0 as the second argument. And what happens then?

convertTemperature(21, 0);

We still get 69.8. But what's going on here? I thought that we specified that we didn't want an decimals in our result?

The problem here is our shortcircuiting statement and how it works. Try to recall our truthy and falsy section and remember what those falsy values were. The problem is that 0 is a falsy value. So as a result, 0 when coerced to a boolean becomes false and we get our default value of 1, which is wrong.

So how do we fix this? As we see here, our function is getting increasingly complex as the requirements for it change. So what's the better way to deal with arguments that aren't provided or falsy values passed as arguments?

The superior approach to avoid such problems is default function values, a feature that also arrived in ES6.

It enables us to say, directly on our parameters, that if an argument isn't provided, and therefore the value is undefined within the function, the default value for that parameter will be used, that is, after the equals operator.

So let's rewrite our code and make 1 our default value on the decimalPoints parameter. And this allows us to remove our shortcircuiting line

functionconvertTemperature(celsius, decimalPlaces = 1) {
   // celsius to fahrenheit
  // decimalPlaces = decimalPlaces || 1;
​ ​  const fahrenheit = (celsius * 1.8) + 32;
  // round result
   return Number(fahrenheit.toFixed(decimalPlaces));}

So to see if we can still call it without a second argument and the default value will be used, we'll call our function again with just degrees:

convertTemperature(21);

[Run code] And we get an answer rounded to 1 decimal place. Great.

And now let's try passing in 0 as our second argument:

convertTemperature(21, 0);

[Run code] And this time, we get 70, with no decimal places, just like we specified. And that's because we're not passing a falsy value to a conditional anymore.

Review

Demands are always changing our applications and the needs of each function you write will also change over time. You'll need to handle cases in which the right arguments are not going to be passed to your functions and default parameters are probably the best way to prevent these errors and to prevent having to write conditionals in your functions to handle undefined arguments.