Everything about Functions in JavaScript

Everything about Functions in JavaScript

Learn about functions in JavaScript along with concepts like pure functions, higher-order functions, and closures

·

6 min read

Functions solve one of the most fundamental problems that humans have, “automating repetitive work”. Understanding functions ensure a happy married life with JavaScript.

So let’s start with creating a function. There are 2 ways to do so:

  • Named function declaration
  • Function expression

Named Function Declaration

To define a function you need the function keyword along with the following things:

  • name - a name for your function. A pro-tip - be concise and descriptive
  • parameters - input variables for your function
  • body - the logic/functionality of your function with a return value
//       name         parameter
//        👇🏽              👇🏽
function getFood(food, quantity) {
  const yourFood = food.repeat(quantity); // 👈🏽 logic
  return yourFood; // 👈🏽 return value
}

If a return value isn’t given it will return undefined.

Calling and Referencing

You can execute a function by calling it using parentheses () and passing the required arguments.

getFood("🥪", 3); // 👈🏽 calling
getFood; // 👈🏽 reference

You can use the reference of a function stored in a variable and use it later and other Higher Order Function things.

Parameters and Arguments

  • Parameters are variable names that you use in the function definition
  • Arguments are the values/expression that are the actual values passed as input in the function call

Function Expression

A function expression is another way of creating a function where an anonymous function is created and the value is assigned to a variable.

//    variable
//        👇🏽
const getFood = (food, quantity) => {
  const yourFood = food.repeat(quantity);
  return yourFood;
};

console.log(getFood("🥪", 3));

Here getFood variable is holding an anonymous function.

Name Function Declaration vs Function Expression

Functions created using function declaration are hoisted whereas function expressions are not. Also, this keyword behaves differently in both cases about which we will learn more in the Arrow Functions section.

Which 🏆 one to use? There isn’t one best but function expressions are more recommended because of:

  • It can be reassigned
  • It can be passed around (Higher Order Functions)
  • Since it's not hoisted, your code will be much easier to understand and debug

This is great, but what’s the modern way of writing functions in JavaScript? ↖️ Arrow Functions.

https://media.giphy.com/media/xT9IgAakXAITtXIWje/giphy.gif

Arrow Functions

The concise and “elegant” way of writing functions in modern JavaScript. Converting regular function to an arrow function:

// Regular function
function getFood(food, quantity) {
  return food.repeat(quantity);
}

// Arrow function
const getFood = (food, quantity) => {
    return food.repeat(quantity);
};

// Directly returning
const getFood = (food, quantity) => food.repeat(quantity);

💡 For returning something directly using the arrow function, wrap it with parentheses ().

const breakfast = () => ({
  food: "🥪",
  quantity: 3,
});

This conciseness is what makes arrow functions so 💪🏽 powerful.

But it’s more than just syntactic sugar for writing functions. There are some nuances that make it different from a regular function like:

  • It will implicitly return the value when you omit curly braces {}. For example: () => true
  • Its always an expression and thus it can’t be hoisted
  • 🔥 It doesn’t have its own this context as regular functions do

The last point has some big implications. To know more about it and arrow functions read my article on How Arrow Functions redefine this in JavaScript.

What’s better, to be pure and impure? Find out in the next section, 👼 Pure Functions.

https://media.giphy.com/media/HhZAlxtIiS01i/giphy.gif

Pure Functions

A pure function is a function that:

  • relies only on its input,
  • produces no side-effects and
  • does not modify variables outside its scope

These conditions make pure functions give the same output for the same input. Functions that don’t adhere to these conditions are termed impure functions.

🤔 What a side-effect? Operations of a function that uses OR modifies non-local states. This makes the function indeterministic. console.log is a side-effect because it prints the output in the console i.e. outside the function.

An example of an impure function:

let x = 0;

const impure = (x) => {
  x = x + 1; // side-effect
  console.log(x); // side-effect
  return x;
};

An example of a pure function:

const pure = (x) => x * 2;

In the above example we get same output from the same input and checks all the conditions for a pure function.

The next topic is what you will be using the most while working with functions in JavaScript i.e. Higher Order Function.

https://media.giphy.com/media/GHycyakNPWSoo/giphy.gif

Higher Order Function

In JavaScript, functions are first-class citizens. This means that:

  • they can be 🔄 passed around and used as arguments for other functions
  • they can be returned from other functions
  • they can be assigned to variables

In the following example, we have used functions like first-class citizens. The callback parameter in the getFood function is a type of code commonly used in JavaScript.

// Assigning a function to a variable
const milkshakeIngredients = () => ({ mango: "🥭", milk: "🥛" });

const getFood = (callback) => {
  const ingredients = callback();
  console.log(ingredients);

  return () => ({ status: "Mango milkshake is ready" }); // returning a function
};

// Passing function as an argument
const result = getFood(milkshakeIngredients);

console.log(result()); // calling the returned function's reference

How to nail down JavaScript interview? By understanding 🍷 Closures.

https://media.giphy.com/media/eMsCxr6w35vjfI4zl5/giphy.gif

Closures

Closures are functions that have access to variables from an outer scope. Whenever you’re defining a function, you’re creating a lexical environment.

  • The inner function will have access to the things defined in outer scopes
  • but the outer objects won’t have access to the inner function’s lexical environment

Consider the following code example to understand how scopes work:

const fish = "🐟";

const outer = () => {
  const crocodile = "🐊";

    // Can access `fish` (from its outer scope) and `crocodile` from its own scope
  console.log(fish);
  console.log(crocodile);

    // ReferenceError: whale is not defined
    // Cannot access whale from `inner` function's scope
  try { console.log(whale); } 
  catch { console.log("cannot access 🐳"); }

  const inner = () => {
    const whale = "🐳";

        // Can access everything from its own and outer scopes
    console.log(fish); 
    console.log(crocodile); 
    console.log(whale);
  };

  inner();
};

outer();

// Output:
// 🐟
// 🐊
// cannot access 🐳
// 🐟
// 🐊
// 🐳

The inner function can access variables from the outer function and the global scope. Whereas the outer function can access value only from the global scope because it's inside that scope but cannot access variables from the inner function's scope.

Now consider the following example of a closure:

const chooseFruit = () => {
  let fruit = "🍎";

  const favFruit = () => {
    console.log(fruit);
  };

  return favFruit;
};

const favouriteFruit = chooseFruit();
favouriteFruit(); // 🍎

In this example, favouriteFruit is a reference of favFruit as chooseFruit returns favFruit function. When you run favouriteFruit it logs 🍎 as output, which it has access to the fruit variable. This is why favouriteFruit is a closure.

Conclusion

Now you know about:

  • 🐥 How to create functions
  • ➡️ Arrow functions
  • 👨‍👩‍👧 High order functions
  • 👼 Pure functions
  • ⚾️ Closures

If you liked this post then do 👍🏼 like and give your 🎙 feedback. ✅ Follow to stay up to date with my new posts.

https://media.giphy.com/media/Scn9X4dqJfBW8/giphy.gif