The demand for functions

Quite often we need to perform a similar action in many places of our program. Let's say we're making a chat application. At the moment, we have the following information--we have the chat participants, listed as user1 and user2, but naturally a chat application is worthless if users aren't able to send message back and forth. And that message needs to have dynamic content that we can reuse. It would truly be impossible to have such an app if we couldn't just provide a way to at any time insert the users name and message that they are sending (without writing it all out manually).

const user1 = "Reed";
const user2 = "Doug";

const message = `User (user) says: (text)`;

So using what we have here, we need to create a kind of program within our program that we can execute as many times as we need. When we have a need for such dynamic behavior and to perform it as many times as we need without repetition, we need to use a function.

You might not have noticed it, but we've been using functions from the beginning. Functions like alert() and prompt that are available on the window object. We can pass certain values to them--in the case of alert and prompt and console.log, we saw that we could pass them strings, and they are totally reusable; we can use them as many times as we like:

console.log("hello world");
console.log("hello world");

So as you can see here, for alert, a function is a process which takes some input, in this case, the text 'hello world', and produces some output.

I like to think of functions as a kind of machine. This machine can accept something, some input, and does something with it. It either performs an action or returns some data (or both).

Functions - Reusable Machines

input (optional) -> performs an action
input (optional) -> returns data

And all we need to do get these reusable machines to work is press the button, or what looks like a button. That is--to take the name of our our function and provide a set of parentheses after it.

Creating our own functions

So how do we make our own functions?

Functions are created or declared with the function keyword. Then after it is the name of the function. Then the input it takes between a set of parentheses, called the parameters. Think of these parentheses like an opening to pass stuff to our machine that it needs. And where is it passed to? The function body, which we create with a set of curly braces. And this is where we put the code that we want the function to run every time we press the button to make it run. Also known as calling our function, or executing it.

function echo(input) {
  console.log(input);
}

So right here, we've made a function called echo, which will echo whatever we provide to it by console.logging the value we pass the function. So to use echo, we call it. And based on our function declaration, we need to provide some data for it to works. We need to provide a value that this 'input' parameter is going to be set to. And we do that by calling our functions with some data, which are called arguments. We can think of passing an argument to be the equivalent here of setting a local variable 'input' to some value with the equals sign. So if we were to pass 42 as the argument, it's going to be provided as the value for the input parameter and then logged:

function echo(42) {
  console.log(42);
}

echo(42);

And if we run this code [Run code] We get 42, which makes sense. But note a couple of things here. When we are passing arguments, the argument will only exist within the scope or context of the function itself. Not in the outer scope outside of the function.

Local variables in functions

Also note that we can declare variables within a function.

And similar to passed arguments, variables declared within a function will be scoped to that function. In other words, a variable made in a function only exists inside that function.

So if we were to make a local variable inside echo, say called greeting:

function echo(input) {
  let greeting;
  console.log(input);
}

echo(42);

If we we were to console.log greeting in the scope above, what do you think we'd get?

function echo(input) {
  let greeting;
  console.log(input);
}

console.log(greeting);
echo(42);

[Run code] We get an error because greeting is scoped to the echo function. This may be pretty straightforward to you, but this is very important. We refer to this feature of all variables as being function scoped, similar to how let and const variables were block scoped.

Outer Variables

But note that a function can access outer variables, too. So if we were to move greeting to any scope outside of echo, we could still use it inside of our function. So let's say the greeting is hi, and we want to console.log our greeting and the input, we can go so as follows:

let greeting = "Hi";

function echo(input) {
  console.log(`Hi ${input}`);
}

echo(42);

When we run this code, what will we get? We get Hi, 42. So we see that we can use input directly passed to functions through arguments as well as through variables and data in any outer scopes.

But what if instead of having greeting be a variable, we passed it as an argument? We can pass as many arguments or individual pieces of data to functions by separating them by commas. So we could directly pass the string Hi to our function as a second argument and remove where we used it earlier:

// let greeting = "Hi";

function echo(input) {
  console.log(`${input}`);
}

echo(42, "Hi");

So when we run this code, what do you think we'll get? [Run code]

We'll just get 42. The reason? JavaScript ignores any additional arguments passed to a function call for which there are no corresponding parameters. So now to use the second argument, we have to create a second parameter whose data it's going to be assigned to. So we'll call this greeting now, and use it like we did before:

function echo(input, greeting) {
  console.log(`${greeting} ${input}`);
}

echo(42, "Hi");

Let's talk briefly about order. Note here that the arguments that we are passing must correspond in number and in order to the function's parameters. The first argument will always be passed to the first parameter, the second argument to the second parameter, etc.

And finally, the last most important thing about function is that they can return values. This means we can use the output of functions to immediately put their resulting data into variables.

For example, how would we use our echo function here to put our created text from the console.log into a new variable called result? Think about this and see if you can come up with an answer.

Well first, after removing the console log, you might have tried to create a result variable, and then try to assign it to the string we created in the function, and then to see if the assignment worked, log result after calling echo.

let result;

function echo(input, greeting) {
  result = `${greeting} ${input}`;
}

echo(42, "Hi");
console.log(result);

[Run code] And we see that this works, but it's a very weak solution. Why? Because we rely on the result variable being reassignable. We couldn't use this solution with const, for example. What we're trying to do is take the value from the function body which is the function's scope into an outer scope. But it's not that difficult. Instead, we can just return the string from echo, which enables us to put the string immediately in a new variable which we can declare:

// let result;

function echo(input, greeting) {
  return `${greeting} ${input}`;
}

const result = echo(42, "Hi");
console.log(result);

And we see that it works just as well and is a lot more readable. Especially if you refer back to our lesson on const makes our code more readable.

One more word about returned values from functions is that even if we don't use the return keyword or intend to return a value from a JS function, the function will return undefined by default. This is just something to be aware of and is visible if we removed the return keyword from echo temporarily:

// let result;

function echo(input, greeting) {
  `${greeting} ${input}`;
}

const result = echo(42, "Hi");
console.log(result);

[Run code]

Now with our deep dive into JS functions, let's come back to the beginning and solve our original problem of our chat app. How can we create a function which displays a message from either one of our users by using message string at the beginning as the template to display first the user's actual name and their message text itself. See if you can write out such a function on your own.

Well first, we'll declare a function with the function keyword, give it a name. And we usually name functions according to what responsibility they have in our app. In this case, we are using it to send a user's message, so we could call it maybe send or create user message. We need to create our parentheses to hold our parameters, to pass any necessary input to our function and then we'll create our function body with curly braces and then perform whatever action or return whatever output we need or both.

So what do we want to do here? We want to take in a user and their message. So we can provide both of those values as arguments. For the first message, maybe user1 will write it, so that will be an outer variable, and it will be passed first to function and then their message, say 'Hey there'. And to pass through the input to our function, we need to create corresponding parameters, which we'll name user and text. And then we can use interpolation to provide them to our message variable. Now we could create a variable here as we saw, but really we just want to display this message to our other user. And we could do that with an alert or console.log for now.

const user1 = "Reed";
const user2 = "Doug";

function sendUserMessage(user, text) {
  console.log(`User ${user} says: ${text}`);
}

sendUserMessage(user1, "Hey there");

And since we know that this function can be called as many times as we like, let's have the second user respond with 'What's up?':

const user1 = "Reed";
const user2 = "Doug";

function sendUserMessage(user, text) {
  console.log(`User ${user} says: ${text}`);
}

sendUserMessage(user1, "Hey there");
sendUserMessage(user2, "What's up?");

And when we run this code [Run code] We see that we have the working start to a chat application, all made possible with the help of functions and their ability to let us reuse this bit of functionality around our app.