Functions can be thought of as one of the core building blocks of our JavaScript programs. A function is simply a set of statements designed to perform a particular task ā€” which is executed whenever it is invoked (or ā€œcalledā€).

In this article weā€™re going to take a look at defining functions, function expressions, calling functions, scope, nesting, closures, the arguments object, function parameters & arrow functions!

Defining functions

A function definition (otherwise known as a function declaration, or function statement) will always begin with theĀ functionkeyword. What follows is theĀ nameĀ of our function, anyĀ parametersĀ enclosed in parenthesis, and then our JavaScriptĀ statementsĀ (enclosed inĀ { }) which are executed when our function is called.

Letā€™s see an example:

function multiply(a, b) {
  return a * b;
}

Our functionĀ multiplyĀ takes two parameters (aĀ andĀ b). Included in-between the curly braces is a statement that returns the result of the first parameterĀ aĀ multiplied by the second parameterĀ b.

Function expressions

There is another way to define a function, known as the function expression. These types of functions can actually beĀ anonymous. They donā€™t need to be given a name.

For example, our previousĀ multiplyĀ function couldā€™ve also been defined like so:

let multiply = function(a, b) { return a * b; };
let x = multiply(2,2); // x returns 4

A typical use case for function expressions might be when passing a function as an argument to another function.

WeĀ canĀ also define a function based on a condition. For example, the following function definesĀ addItemĀ only ifĀ numĀ equals 1:

let addItem;
if (num === 1) {
  addItem = function(shoppingList) {
    shoppingList.item = 'Apples';
  }
}

Calling functions

When we define a function all weā€™ve done is given it a name & specified what to do when the function executes. So to actually run the function, weā€™ll need to call it within our program!

To call our earlier functionĀ multiply, we could invoke it as follows:

multiply(2,2);

Here weā€™re calling our function which is set to receive two arguments with the arguments ofĀ 2Ā andĀ 2. The function executes and runs its statements which returns the result ofĀ 4(2 multiplied by 2).

Functions need to be in scope when they are called, but the function declaration can be hoisted (appear below the call in the code), like so:

console.log(multiply(2,2));
/* ... */
function multiply(a,b) { return a * b; }

The scope of a function is the function in which it is declared, or the entire program if it is declared at the global level.

Note:Ā This only works with function declarations. Not function expressions!

Function scope

When variables are defined inside a function they cannot be accessed anywhere outside of that function. As that would be outside the scope. However, a function is able to access all variables and functions defined inside the scope in which it is defined. So a function defined in the global scope can access all variables defined in the global scope. A function defined inside another function can also access all variables defined in its parent function and any other variable to which the parent function has access.

Letā€™s see an example...

// These variables are defined globally (global scope)
let a = 10,
    b = 3,
    name = 'Bruce';
// This function is defined globally 
function multiply() {
  return a * b;
}
multiply(); // returns 30
// Working with a nested function
function multiplyAssign() {
  let a = 20,
      b = 6;
  
  function add() {
    return name + ā€˜ receivedā€™ + (a * b);
  }
  
  return add();
}
multiplyAssign(); // returns "Bruce received 120"

Nesting functions and closures

So you can nest a function within a function!Ā The nested (inner) function is private to its containing (outer) function. It also forms aĀ closure.Ā A closure is an expression (usually a function) that can have free variables together with an environment that binds those variables (it ā€œclosesā€ the expression).

And as a nested function is a closure, itā€™s able to ā€œinheritā€ the arguments and variables of its containing function.

As follows:

function addSquares(a, b) {
  function square(x) {
    return x * x;
  }
  return square(a) + square(b);
}
a = addSquares(2, 3); // returns 13
b = addSquares(3, 4); // returns 25
c = addSquares(4, 5); // returns 41

Since the inner function forms a closure, you can call the outer function and specify arguments for both the outerĀ andĀ inner function!

Closures

As we now know, we can nest our functions and JavaScript will give the inner function full access to all the variables and functions defined inside the outer function (as well as all variables & functions that it has access to).

However, the outer function does not have access to the variables and functions defined inside the inner function!Ā AĀ closureĀ is created when the inner function is somehow made available to any scope outside the outer function.

Letā€™s see an example:

// The outer function defines a "name" variable
let user = function(name) {   
  let getName = function() {
    return name;             
    // The inner function can access the "name" variable of the  outer function
  }
// Return the inner function, and expose it to outer scopes
return getName;            
}
makeAdmin = user('Steve Stevesson');
   
makeAdmin(); // returns "Steve Stevesson"

The arguments object

The arguments of any function are maintained in anĀ array-likeĀ object. Within a function, you can address the arguments passed to it as follows:

arguments[i]

HereĀ iĀ is the first number of the argument, starting at zero. So, the first argument passed to a function would beĀ arguments[0]. The total number of arguments would beĀ arguments.length.

Using theĀ argumentsĀ object, you can call a function with more arguments than it is formally declared to accept. This is often useful if you don't know in advance how many arguments will be passed to the function.Ā You can useĀ arguments.lengthĀ to determine the number of arguments actually passed to the function, and then access each argument using theĀ argumentsĀ object.

For example, consider a function that concatenates several strings. The only formal argument for the function is a string that specifies the characters that separate the items to concatenate. The function is defined as follows:

function myConcat(separator) {
   let result = ''; // initialize list
   let i;
   // loop through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}

You can pass any number of arguments into this function, and itā€™ll concatenate each argument into a string ā€œlistā€:

myConcat(', ', 'fred', 'wilma', 'barney', 'betty');
// returns "fred, wilma, barney, betty, "
myConcat('; ', 'marge', 'homer', 'lisa', 'bart', 'maggie');
// returns "marge; homer; lisa; bart; maggie; "
myConcat('. ', 'jerry', 'kramer', 'elaine', 'george', 'newman');
// returns "jerry. kramer. elaine. george. newman. "

Note:Ā TheĀ argumentsĀ variable is "array-like", but not an array. It has a numbered index and aĀ lengthĀ property. However, it does not possess all of the array-manipulation methods.

Function parameters

There are two kinds of function parameters:Ā defaultĀ parameters andĀ restĀ parameters. Letā€™s now take a look at each...

Default parameters

In JavaScript, parameters of functions will default toĀ undefined. However, in some situations, it might be useful to set a different default value. This is where default parameters are useful.

Itā€™s actually quite simple to implement:

function multiply(a, b = 1) {
  return a * b;
}

multiply(10); // 10

You can simply putĀ 1Ā as the default value forĀ bĀ in the function head.

Rest parameters

The rest parameter syntax allows us to represent an indefinite number of arguments as an array.

In this example, we use the rest parameters to collect arguments from the second one to the end. We then multiply them by the first one. This example uses an arrow function, which weā€™ll look at next!

function multiply(multiplier, ...theArgs) {
  return theArgs.map(x => multiplier * x);
}

let arr = multiply(2, 1, 2, 3);
console.log(arr); // [2, 4, 6]

Arrow functions

An arrow function has aĀ muchĀ shorter syntax compared to function expressions. For example, here is a regular function:

function funcName(params) {
  return params + 10;
}

funcName(2); // 12

And here is the same function, expressed as anĀ arrow function:

let funcName = (params) => params + 10

funcName(2); // 12

The same function in just one line of code! Pretty neat!

If we have no parameters, we express our arrow function like this:

() => { statements }

And when we have just one parameter, the opening parenthesis are optional:

parameters => { statements }

Finally, if youā€™re returning an expression, you can remove the brackets:

parameters => expression

// is the same as:

function (parameters){
  return expression;
}

Note:Ā Unlike a regular function, an arrow function does not bindĀ this. Instead, thisĀ is bound to keep its meaning from its original context. Weā€™ll be taking a closer look at the ā€œthisā€ keyword in an upcoming article!

Predefined functions

Itā€™s well worth noting that JavaScript has numerous built-in functions! And theyā€™ll likely save you a lot of time, especially for common tasks. See:
https://www.tutorialspoint.com/javascript/javascript_builtin_functions.htm

Wrapping up

And thatā€™s all for today! Weā€™ve learned about defining functions, function expressions,Ā callingĀ functions, scope, nesting, closures, the arguments object, function parameters & arrow functions!

Related Posts:


Tim profile image

A little about me..

Hey, Iā€™m Tim! šŸ‘‹

Iā€™m a freelance business owner, web developer & author. I teach both new and experienced freelancers how to build a sustainable and successful freelancing business. Check out myĀ Complete Guide to Freelancing if you'd like to find out more.

While you're here, you can browse through my blogs where I post freelancing tips, code tutorials, design inspiration, useful tools & resources, and much more! You can also join the newsletter, or find me on X.

Thanks for reading! šŸŽ‰