Functions - Parameters and Arguments

Beginner JavaScript

Enjoy these notes? Want to Slam Dunk JavaScript?

These are notes based on my Beginner JavaScript Video Course. It's a fun, exercise heavy approach to learning Modern JavaScript from scratch.

Use the code BEGINNERJS for an extra $10 off.

BeginnerJavaScript.com

This video will focus on arguments and parameters.

In the calculateBill() function from the previous video, we hardcoded the tax amount.

A best practice in JavaScript is to keep your code DRY, which stands for Don't Repeat Yourself.

calculateBill would not be useful if it could only calculate the value assuming the bill is $100 and a 15% tax rate, so we need to modify those hardcoded values.

To solve that, above the calculateBill function, we can declare variables for the bill total and taxRate.

Modify the code like so πŸ‘‡

const bill = 100;
const taxRate = 0.13;

function calculateBill() {
  console.log("Running calculate bill!!");
  const total = bill * taxRate;
  return total;
}

This will work, but that is not the best way to do it. Why?

calculateBill is relying on something called global variables (which will be explained in future videos).

For right now, what you need to know is that calculateBill needs some data. When it is not passed data, it is instead reaching outside of the function in order to look up that data in a higher scope.

That is not great practice (reaching outside of a function in order to get your data).

In cf.js, remove the last console.log and add the following πŸ‘‡

const myTotal = calculateBill();
const myTotal2 = calculateBill();
console.log(myTotal, myTotal2);

TIP: You can log as many pieces of data as you want by separating the values with commas like in the example above.

The log will return the same value:

$100.13.

What if we wanted a different value? Could we do something like this? πŸ‘‡

const myTotal = calculateBill();
bill = 200;
const myTotal2 = calculateBill();
console.log(myTotal, myTotal2);

(Note: you need to change the bill variable that is declared in cf.js to a let instead of a const so we can reassign a new value to it)

If you refresh it, now it works.

However, we have been changing the variable by modifying our code each time we want to run it with different values. This is bad practice and it is how you get very brittle applications.

What we want to do is instead of reaching out, we will pass the data that we need into our functions.

First let's do a bit of cleanup. Get rid of the let bill and const taxRate variables. Get rid of lines of code where we are reassigning variables and declaring myTotal2 (bill = 200; const myTotal2 = calculateBill()) and the last log.

You should end up with the following code πŸ‘‡

// function definition
function calculateBill() {
  // this is the function body
  console.log("Running Calculate Bill!!");
  const total = bill * 1 + taxRate;
  return total;
}

const myTotal = calculateBill();

Now we want to take the variables bill and tax rate and we want to make them into something called parameters or params for your function.

When you define your function, you add params which let you know that the function expects to be passed some data. Wes likes to think of params as placeholders.

function calculateBill(billAmount, taxRate)

Inside of the function body, we will have access to the two variables that were passed:

  • billAmount
  • taxRate

It can be confusing because there is no "creation of the param variables", but Wes will do his best to explain it.

// function definition
function calculateBill(billAmount, taxRate) {
  // this is the function body
  console.log("Running Calculate Bill!!");
  const total = billAmount * (1 + taxRate);
  return total;
}

const myTotal = calculateBill(100, 0.13);
console.log(myTotal);

That will give you $113.

But now we are able to make a myTotal2 really quickly πŸ‘‡

const myTotal = calculateBill(100, 0.15);
const myTotal2 = calculateBill(200, 0.13);
console.log(myTotal, myTotal2);

It works without having to reassign because when you define a function, you can place parameters. P = placeholder is one way to remember it.

When you call the function, you pass it arguments.

Here is a quick cheatsheet Wes has put together that explains the parts of a function.

function definition includes function keyword, name, paraeters, default value, body, return value and scoping

When we define the function, we use what are called parameters. Parameters can be thought of as placeholders (we will talk about default values for parameters shortly).

When you call, run or invoke (all 3 mean the same thing), and you actually pass it the data, that will take place of the variables (for example meal will be 100 and taxRate will be 0.13), those will be called arguments.

People incorrectly use those terms interchangeably. One way to remember is that parameters are placeholders. The actual values that you pass in when calling a function are what are called arguments.

Bringing it back to const myTotal = calculateBill(100,0.13), here we are running the function and as arguments we are passing straightaway numbers. However, the values that get passed into a function can be in a variable as well. This is a common thing people get hung up on when learning how functions work is how they sort of get renamed.

Let's take a look at code we wrote for calculateBill().

The data gets passed into the function, and those variables are only available inside of the calculateBill function. They will be what is called scoped to the function, which means only available inside of the function.

If we add a log within calculateBill like so πŸ‘‡

// function definition
function calculateBill(billAmount, taxRate) {
  console.log(billAmount, taxRate);
  // this is the function body
  console.log("Running Calculate Bill!!");
  const total = billAmount * (1 + taxRate);
  return total;
}

const myTotal = calculateBill(100, 0.13);

calculateBill function computes the bill using scoped arguments as 100 for billAmount and 0.13 for taxRate

We can run that function from the console but pass it different values for the arguments, it will console log the values of the arguments that we passed, like so πŸ‘‡

calling calculateBill function again by passing different arguments

Why?

Because JavaScript will take whatever you write as an argument, and then when you call the function it will make it sort of temporarily available to you via the names that you put in your parameters.

What gets a little bit confusing to people is if we declare two variables before we call the function like so πŸ‘‡

const wesTotal = 500;
const wesTaxRate = 0.3;
const myTotal = calculateBill(100, 0.15);

We can actually pass those variables into the function like this πŸ‘‡

const wesTotal = 500;
const wesTaxRate = 0.3;
const myTotal = calculateBill(wesTotal, wesTaxRate);

Now the big confusion is, if they are variables outside of the function, and we pass them into the function, when it's called inside of the function, is the first parameter called billAmount or is it called wesTotal?

Will it even work if you pass in a variable that does not have the same name as the parameter? Try refreshing index.html in the browser.

You should see it works just fine!

To review, when you run a function in JavaScript, what happens is JavaScript takes in whatever you have passed it, whether you have passed it that value directly (as a number or string for example), or if you pass it in via reference (meaning that you just passed a reference to a variable which in turn will hold a value).

At the end of the day we are still passing values, whether you pass it directly or whether you pass it a reference to a variable that holds a value. JavaScript doesn't care about how you are passing them in, whether as a value directly or as a variable.

In this function, JavaScript will take whatever was passed in the first argument and make it into a temporary variable billAmount that is available inside of the confines of the curly brackets.

When the function is running, it does not care about anything else that is going outside of this function. It just knows it's doing its job, it's been passed in the 2 little pieces of data that it needs, it does the math and returns its value from within the function.

When values get passed into a function, they sort of get renamed into whatever it is that you have defined your function parameters as.

Another Example

Let's do another example!

Comment out the code const myTotal = calculateBill....

Add the following function to your code, which just returns hello and which we will pass in someone's first name πŸ‘‡

function sayHiTo () {
  return `Hello ${firstName}`;
}

const greeting = sayHiTo();
console.log(greeting);

Run the code as is, even though it will break, to see why. In the console you should see a reference error in the console.

sayHiTo function throws not defined error as firstName is not defined anywhere

What happens is this function, first it looks inside of its own function scope, and it will look for a variable firstName that has been passed in. If there is not, it will start to do is go up to a high level of scope and look there.

Let's say there was a firstName variable like so πŸ‘‡

const firstName = "wes";

function sayHiTo () {
  return `Hello ${firstName}`;
}

const greeting = sayHiTo();
console.log(greeting);

That would work, because the function will reach outside for that data if nothing is found within the scope of that function.

What we want to do is modify the function definition to set it to take in one parameter (firstName). And then when we run the function, we actually have to pass it a string (we will use Wes), and then we will have our greeting.

const firstName = "wes";

function sayHiTo (firstName) {
  return `Hello ${firstName}`;
}

const greeting = sayHiTo("Wes");
console.log(greeting);

This makes the function nice and reusable, and we can use it to print out any first name like so πŸ‘‡ reusing same function named sayHiTo by passing different first name

As long as we pass in an argument (in this case "Wes"), it is going to have a variable inside of that function that is referenced to whatever the person has passed in.

If we don't run it with anything, you will see... πŸ‘‡

without passing an argument to sayHiTo function which accepts a parameter prints undefined

The reason that happens is when a function runs, it will create the variable for us (firstName) and set it to whatever was passed in.

But if it creates a variable and someone doesn't pass in anything, then it will just be set to undefined which is exactly how variables work.

Even More Examples

Now let's go over a few more examples.

Let's go back to passing expressions. For this example we will go back to calculateBill.

// const greeting = sayHiTo('Wes');
// console.log(greeting);
const myTotal3 = calculateBill(100, 0.15);

We know the code above works but what if instead we do πŸ‘‡

const myTotal3 = calculateBill(20 + 20 + 30 + 20, 0.15);

Is that going to work?

If you load index.html in the browser you will see 103.4999999999.

(If you followed Wes too closely, you may have gotten the value of 90.5. If that is the case, the line of code that calculates the total within calculateBill. It should be const total = billAmount * ( 1 + taxRate);. This is because of bedmas, we need the parenthesis).

That works.

Why?

Because the only thing that a function can take in is a value, and whether you pass that value directly, as in a number, whether you pass that value in as a variable which holds a value, that works, and then you can also pass in expressions.

In this example we are not actually passing an expression, we are actually running an expression and that will first run (20 + 20 + 30 + 20) and add it up to $90, and then we pass that raw value of 90.

It is absolutely fine to do something that like, in fact it is pretty common.

You can even mix and match.

Let's say we have a variable const kait = 100; and then we want to add another $50 on top of that. You can do something like..

const kait = 100;
const myTotal3 = calculateBill(kait + 50, 0.15);

It still works, even though we are mixing and matching.

Let's remove the myTotal3 example, and do another example where we pass functions as arguments.

Make a function doctorize which will take in a name argument and return the name with "Dr." in front like so πŸ‘‡

function doctorize(name) {
  return `Dr. ${name}`;
}

And we will make another function called yell that also takes in a name and returns "HEY" with the variable name uppercase like so πŸ‘‡

function yell(name) {
  return `HEY ${name.toUpperCase()}`;
}

You might have noticed that both functions are using the variable name.

While it's not okay to reuse variables in the same scope multiple times, it is okay to reuse parameters.

Why? Because when arguments are passed in, the parameters are only available within that function so you will never run into a collision where the name that you pass into one function is going to overwrite it in the other function. That will not happen because parameters are scoped to the confines of their own functions.

The name parameter that is used in the doctorize() method will never collide with the variable within the yell() method.

Let's go ahead and run it in the console. πŸ‘‡

reusing same name as parameters across different functions never collide with each other

Let's pass the output of doctorize() into yell by typing the following into the console πŸ‘‡

yell(doctorize('wes'))

in nesting of functions calls inner function gets executed first, followed by outer function

How that works is:

  • brackets go first. anything in between the yell parenthesis yell() the code says "okay, I need to first run this function first" , and hopefully that returns a value (which it does, it returns Dr. + the value of the name argument passed)
  • then the value that is returned from doctorize immediately gets passed into yell as an argument and then that will in turn return "Hey Dr. Wes".

So to recap -- another way we can pass a value to a function that is the output of a function, because that is just a value at the end of the day and you can run that directly like demonstrated here.

Default Values

Now, let's talk about default values.

If we were to take our yell function and instead of passing it "Wes", we do not pass an argument, it will error out.

yell function without argument results in error

What is happening is that the toUpperCase() function (it's technically a method), it's trying to run it against something that didn't get passed in. This means that if someone forgets to pass a value to the yell function, our code will break.

What we can do is we can set something called defaults. When you define your function, inside of your function definition, you can set a default by saying name is equal to 'Silly Goose', as shown below.

function yell(name = "Silly Goose") {
  return `HEY ${name.toUpperCase()}`;
}

If you run it and pass an argument, it will still work.

However, when you run it without an argument, the function will no longer error out and instead will fall back to the default value for the parameter and output HEY SILLY GOOSE.

So as you define your function, you can specify if someone does not pass this parameter name, use the default.

Let's go back to our calculateBill function.

You may be thinking that it's a bit silly to have to pass in the the tax rate every single time. We will use a default value to set a default tax rate of 0.13, by modifying the function like so πŸ‘‡

// function definition
function calculateBill(billAmount, taxRate = 0.13) {
  // this is the function body
  console.log("Running Calculate Bill!!");
  const total = billAmount * (1 + taxRate);
  return total;
}

What that allows us to do is call calculateBill(100) and only pass the value for the billAmount.

by giving taxRate as default value we can omit taxRate argument in function call

Wes often likes to set default values when he is creating functions. Even just adding a default value for a string variable of an empty string.

function yell(name = "") {
  return `HEY ${name.toUpperCase()}`;
}

That will make sure the function doesn't error out, it just won't show a name like so πŸ‘‡

setting default values to function parameters ensures no errors when no actual argument is passed

That is just a safeguard.

Let's take it one step further and modify calculateBill to also take in a tip rate.

Add another argument with a default value tipRate = 0.15 πŸ‘‡

// function definition
function calculateBill(billAmount, taxRate = 0.13, tipRate = 0.15) {
  // this is the function body
  console.log("Running Calculate Bill!!");
  const total = billAmount * (1 + taxRate);
  return total;
}

Now we will change the way we calculate total like so πŸ‘‡

const total = billAmount + billAmount * taxRate + billAmount * tipRate;

You may notice that as you save the file, Prettier will remove the parenthesis if they are not needed (the BEDMAS rules are not needed here)

BEFORE SAVING πŸ‘‰

parenthesis included before saving without prettier

AFTER SAVING WITH PRETTIER πŸ‘‰

parenthesis gets removed after saving with prettier

If we run calculateBill and pass it 100 dollars, it will return 128.

How to Fall Back on Default for Only One Parameter

A gotcha that happens here is what if you want to use the default tax rate but not the default tipRate?

const myBill4 = calculateBill(100, , 0.2);

If you try to just leave the argument empty and use two commas like shown above πŸ‘†, it will break.

leaving the second argument empty results in breaking the code

πŸ‘† The error is complaining about an unexpected token ,.

So the only thing that you can pass into a function to cause it to use the default is undefined. A function will only ever fall back to the defaults if nothing is passed.

Remember when a variable is not set to anything, its value is undefined. So you cannot go ahead and pass zero here and expect it to false back to the default.

const myBill4 = calculateBill(100, undefined, 0.2);

You have to actually pass it undefined, πŸ‘† as shown above, and it will work as we intended.

It's very infrequently that you have to pass undefined like that but it's worth knowing how a function decides whether or not to fall back on a default.

It has nothing to do with truthy or falsy which we will be learning soon.

Find an issue with this post? Think you could clarify, update or add something?

All my posts are available to edit on Github. Any fix, little or small, is appreciated!

Edit on Github

Syntax Podcast

Hold on β€” I'm grabbin' the last one.

Listen Now β†’
Syntax Podcast

@wesbos Instant Grams

Master Gatsby

Master Gatsby

Building modern websites is tough. Preloading, routing, compression, critical CSS, caching, scaling and bundlers all make for blazing fast websites, but extra development and tooling get in the way.

Gatsby is a React.js framework that does it all for you. This course will teach you how to build your websites and let Gatsby take care of all the Hard Stuffβ„’.

MasterGatsby.com
I post videos on and code on

Wes Bos Β© 1999 β€” 2021