Functions in JavaScript or any programming language are modular building blocks for creating powerful and modular scripts, using function makes it easy to isolate a code since it would be packaged up into a single unit, and you can then call the function whenever and wherever it is needed.
If you are wondering why functions are super useful, here are some uses:
- It can help make your script more readable and avoid writing the same code multiple times, this is called re-usability, once a function is coded, it can be applied multiple times in the script. You can also port it to another script.
- Instead of sifting through long spaghettis of code, functions make it easier to figure out what a particular part of code is supposed to do.
Introduction and Syntax
The syntax for defining a function:
function function_name($arg1, $arg2, ...) {
// statements;
}
The definition starts with function, the function name with parenthesis which encloses our argument list (the arguments are optional), these are the arguments the function is going to accept, make sure they are separated by a comma as you can see in the example above.
The statement is the meat of the function, it contains all of the code you want the function to do, and the good thing about using a function is that the code would be reusable, and you would be able to call the function from a lot of different places.
Below is an example of a function that greets our users:
function greet() {
console.log("Hello World");
}
By default, the above isn’t going to do anything, well, we only defined the function and added the console.log statement, you might not realize it, but what we actually did is stored the functions in memory for later use, so, whenever you want to use the function, you need to call it, so, here is how it is done below:
function greet() {
console.log("Hello World");
}
greet(); // Calling the function greet
// => Hello World
Easy enough. We called the function greet, it then prints “Hello World” make sure the parenthesis is there, otherwise, it won’t work, so, make sure you have greet(); and not greet;
Let's try a function with an argument:
function userinfo($name) {
console.log(`My Name Is ${name}`);
}
In the above example, I added one argument name, that is readily available in the function block which contains a single statement that prints a string with a template literal (${name}), so, what happens here is that, whatever the user passes into the function userinfo(), it would be accessible inside the function, which would then make it executes whatever is inside the function.
To make use of this, you pass a string into the function, the below is an example:
function userinfo(name) {
console.log(`My Name Is ${name}`);
}
userinfo("James"); // Calling The Function userinfo with a paramter
// => My Name Is James
You see how flexible that is, that is one of the main advantages of using a function, you can reuse the code, and make your life easier.
Also, you don’t have to pass in a string, you can pass in a variable that contains the string, e.g:
function userinfo(name) {
console.log(`My Name Is ${name}`);
}
myName = "James";
userinfo(myName); // Calling The Function userinfo with a paramter
// => My Name Is James
The functions assign whatever is in the variable myName, into the name which is the function argument, so, it doesn’t have to match.
Let’s try a function with more than one argument:
function fix_names(n1, n2) {
n1 = n1.charAt(0).toUpperCase() + n1.substring(1).toLowerCase();
n2 = n2.charAt(0).toUpperCase() + n2.substring(1).toLowerCase();
console.log(`Your Full Name Is: ${n1} ${n2}`);
}
fix_names("chARles", "babBaGe"); // Calling The Function fix_names with two parameters
// => Your Full Name Is: Charles Babbage
The above function clean up the user Full Name, so, even if the user passes a string like so: “saMueL”, it would get converted to “Samuel”, Here is how it works:
- n1.charAt(0) gets the first character, we then converts the first character to an uppercase: n1.charAt(0).toUpperCase() would give use "C"
- We concatenated the strng + , we then use ns1.substring(1) to slice out the first character, we don't need it in the appended string, lastly, we use toLowercase to converts the rest of the string to lowercase, so, n1.substring(1).toLowerCase() would give us: "harles"
- Together: n1 = n1.charAt(0).toUpperCase() + n1.substring(1).toLowerCase(); I get Charles.
As you can see we are using two arguments, so the user would need to supply two parameters when calling the function as we've done above.
Return Values from A Function
Well, we’ve seen a bit of flexibility with using a function, but really, all we’ve done is basically printing out the result of whatever gets passed into the function. What if we would like to get a result from the function, and then decide what to do with that result ourselves, so, in that scenario, we don’t want the function to output the result for us, but instead we want to choose when to do the output, to do that, we need to understand how to return values from a function.
Typically, the output produced by a function would practically go on to the screen when called, but you can actually get it to go somewhere else, you can send the output of a function to another function, another interesting thing you can do is to return the output of a function, and store it in a variable, which you can then use later for further processing.
Here is how it works:
function multiply(n1, n2) {
total = n1 * n2;
return total;
}
console.log(multiply(3,4));
// => 12
Instead of telling the function to log the result in the console, we return the value to whatever control is calling it, you can as well store the returned value into a variable, and perform more processing on it, e.g:
function multiply(n1, n2) {
total = n1 * n2;
return total;
}
returned = multiply(3,4);
console.log(returned + 5);
// => 17
You can see how this gives us more flexibility, when the function returns a value, it immediately exit the function, so keep that at the back of your mind.
If you do not pass any parameter, you'll get an undefined value like so:
function multiply(n1, n2) {
return 'Hello ' + n1 + ' ' + n2;
}
console.log(multiply());
// => Hello undefined undefined
In that scenario, you can use a default value, something like this:
function name(n1, n2) {
if(typeof n1 === 'undefined'){n1 = 'First_Name'}
if(typeof n2 === 'undefined'){n2 = 'Second_Name'}
return 'Hello ' + n1 + ' ' + n2;
}
console.log(name());
// => Hello First_Name Second_Name
This is very clunky, a better way to do this is to supply the default value in the argument like so:
function name(n1 = 'First Name', n2 = 'Second_Name') {
return 'Hello ' + n1 + ' ' + n2;
}
console.log(name());
// => Hello First_Name Second_Name
Return Multiple Values from A Function
A function can only return a single value, it would be cool to return multiple values, maybe by calling return 1, return 2, etc, unfortunately, it doesn’t work that way, but there is a way we can actually return multiple values from a function, the way we can do this is to think of a single entity that can hold more than one thing, and as you might have guessed, it is an array, we can return an array, and that can hold more than one value for use, the below is an example:
function math(n1, n2) {
mult = n1 * n2;
add = n1 + n2;
return [mult, add];
}
math_array = math(5,5);
console.log("Mult: " + math_array[0]);
console.log("Add: " + math_array[1]);
// Output
// => Mult: 25
// => Add: 10
We use the array as a mechanism to return more than one value from the function, and that is because arrays are built to handle the collection of objects.
Another way you can break down the array returned from a function is to use destructuring assignment syntax. This is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. so, instead of relying on a single variable as we’ve done above, we can use a destructing assignment to break them down, e.g:
function math(n1, n2) {
mult = n1 * n2;
add = n1 + n2;
return [mult, add];
}
let [a, b] = math(5,5);
console.log("Mult: " + a);
console.log("Add: " + b);
// Output
// => Mult: 25
// => Add: 10
You can see how less clunky that is, it is not really hard to understand, the way it works is that it takes the values from the function arguments, in our case it is: math(5,5), and then assigns them to the destructuring variables in the left hand side which in our case is: a, and b, so, by doing that, we can then make use of it, which we did below the list line, here:
console.log("Mult: " + a);
console.log("Add: " + b);
This just makes things a bit more easier, instead of relying on the array indexes.
Here are more examples of destructuring assignment:
let a, b, rest;
[a, b] = [10, 20];
console.log(a);
// expected output: 10
console.log(b);
// expected output: 20
[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(rest);
// expected output: Array [30,40,50]
Learn more: Destructuring Assignment
Function Expressions
A function expression is almost like a function declaration (the one we've been doing), in fact, it has almost the same syntax, The main difference between a function expression and a function declaration is the function name, which can be omitted in function expressions to create anonymous functions. A function expression can be used as an IIFE (Immediately Invoked Function Expression) which runs as soon as it is defined.
Here is an example:
const multiply = function (n1 = 3, n2 = 2) {
return n1 * n2;
};
As you can see, we set the function to a variable multiply, the function can either be named e.g function multiply or it can be anonymous, as per above, the function is anonymous. Make sure you add a semicolon at the end of the curly bracket as it's a variable.
To use this, we do:
const multiply = function (n1 = 3, n2 = 2) {
return n1 * n2;
};
console.log(multiply());
// => 6
Function expressions in JavaScript are not hoisted, unlike function declarations. You can't use function expressions before you create them:
console.log(multiply()); // undefined
// => Uncaught ReferenceError: Cannot access 'multiply' before initialization
const multiply = function (n1 = 3, n2 = 2) {
return n1 * n2;
};
Even though the variable name is hoisted, the definition isn't. so it's undefined.
Let's talk about Immediatley invokable function expressions - IIFE. An IIFE is a function that you define and run immediately. Here is an example:
(function(){
console.log('IIFE Defined and Run Immediately');
})();
// => IIFE Defined and Run Immediately
To use IIFE, it needs to be in an expression, which is what I enclose it in opening and close bracket (function() {...}) To make it complete, you need to add (); at the end, otherwise, it won't work.
You can add a parameter like so:
(function(name){
console.log('Hello '+ name);
})(' World');
// => Hello World
Super classic.
You can also put function inside an object, we've done this before in the guide: Basics of Object Literals
const todo = {
add: function(){
console.log('Add Todo...');
},
edit: function(id){
console.log(`Edit todo ${id}`);
}
}
// Reference The Function Like so
todo.add(); // => Add Todo...
todo.edit(10); // => Edit todo 10
You can also define the function outside of the todo object like so:
const todo = {
add: function(){
console.log('Add Todo...');
},
edit: function(id){
console.log(`Edit todo ${id}`);
}
}
// Reference The Function Like so
todo.add(); // => Add Todo...
todo.edit(10); // => Edit todo 10
todo.delete = function(){
console.log('Delete Todo...');
}
todo.delete(); // => Delete todo...
or you can use an IIFE:
todo.delete = (function(){
console.log('Delete Todo...');
})();
// => Delete Todo...
Variable Scope
Variable scope refers to the visibility of variables, meaning which parts of your code can see or use the variable, there are mainly two type of variable, and that is the local and global variable scope.
A variable created inside the function is by default only accessible in the function, you won’t be able to use such variable outside of the function, which is why we say such variable is local to the function, let’s see an example of a global and local variable scope:
// Global Scope
var x = 1;
let y = 2;
const z = 3;
function scope() {
var x = 4;
let y = 5;
const z = 6;
console.log('Function Scope: ', x, y, z); // => Function Scope: 4 5 6
}
scope();
console.log('Global Scope: ', x, y, z); // => Global Scope: 1 2 3
In the function, we are referring to the variables inside the function, and outside the function, we are referencing the variable outside of the function. Becareful, the way Global scope works in JavaScript is a bit different from say PHP, take a look at the following example:
// Global Scope
var x = 1;
let y = 2;
const z = 3;
function scope() {
console.log('Function Scope: ', x, y, z); // => Function Scope: 1 2 3
}
scope();
console.log('Global Scope: ', x, y, z); // => Global Scope: 1 2 3
If you declare a variable outside of a function, and you do not define the variable inside of the function, you can still use the variable since it is assumed global, that was the reason we had the above output. In PHP, you'll use the Global keyword plus the variable name to access it in the function, but this is different in JavaScript, so, take a caution.
They'll always be a different variable if and only if you define them in both local and global scope, hope you get that.
There is also a block level scope, e.g a loop or anything wrapped in a curly braces:
// Global Scope
var x = 1;
let y = 2;
const z = 3;
if(true) { // Block Scope
var x = 7;
let y = 8;
const z = 9;
console.log('If Scope: ', x, y, z); // => If Scope: 7 8 9
}
console.log('Global Scope: ', x, y, z); // => Global Scope: 1 2 3
So, again, if you do not define a block scope variable it would assume global:
// Global Scope
var x = 1;
let y = 2;
const z = 3;
if(true) { // Block Scope
console.log('If Scope: ', x, y, z); // => If Scope: 1 2 3
}
console.log('Global Scope: ', x, y, z); // => Global Scope: 1 2 3
Hope you get it, I know, JavaScript scope can really get messed up, also, I'll advise to steer clear of var, and use let and const instead as var can really mess things up.