const - JS | lectureA Closer Look At Functions

Immediately Invoked Function Expressions (IIFE)

A Closer Look At Functions

Sometimes in JavaScript, we need a function that is only executed once and never again. So basically, a function that disappears right after it's called once. This might not make much sense right now, but we will need this technique later. For example, with something called async/await.

Let's say we have this below function:

script.js
const sayHello = function () {
  console.log('Say hello once!');
}

sayHello();

Writing such a function makes it possible to call it again at some point in the code if we want to. But that's not what we want to do. We want to execute a function immediately. And we don't want to save the function somewhere.

To achieve that, here is how we do it.

script.js
/**
 * IIFE Pattern

 1. First, we create a function expression. We will get an error saying
    function statement requires a name.

    function () {
        console.log('Say hello once!');
    }

 2. We trick JavaScript to think that it's a function expression by
    adding parentheses.

    (function () {
        console.log('Say hello once!');
    })

1. We immediately call the function.

    (function () {
        console.log('Say hello once!');
    })()
*/

(function () {
  console.log('Say hello once!');
})();

The same would also work for an arrow function.

script.js
(() => {
  console.log('Say hello once!');
})();

Now the question is why was this pattern invented? Well, we already know that functions create scopes, and what's important here is that the global scope does not have access to variables from an inner scope. For example, consider the following code:

script.js
// Global scope

(function () {
  // Inner scope
  // The isPrivate variable is encapsated.
  const isPrivate = 1;
  console.log(isPrivate);
})();

console.log(isPrivate); // ReferenceError

In the global scope, we do not have access to the variable isPrivate defined in the inner scope of the IIFE. That's because the scope chain works the other way around. That is, the inner scope would have access to anything defined outside in the global scope. Hence, we say that all data defined inside a scope is private. We also say that data is encapsulated.

Data encapsulation and data privacy are extremely important concepts in programming. Most of the time, we actually need to protect our variables from being accidentally overwritten by some other parts of the program, external scripts or libraries. We are actually going to talk in detail about these concepts very soon.

For now, keep in mind that it's important to hide variables. And that scopes are a good tool for doing this. And this is also the reason why Immediately Invoked Function Expressions were invented. It is not really a feature of the JavaScript language. It's more of a pattern that some developers came up with and that started to be used by many other developers.

Now, do you remember what also creates a scope in ES6? Variables declared with let or const create their own scope inside a block. We learned that when we talked about how JavaScript works behind the scenes.

So when we create a block, like this:

script.js
// Global scope
{
  const isPrivate = 1;
}

console.log(isPrivate); // ReferenceError

Then the global scope can still not access the isPrivate variable. While on the other hand, if we create a block like this:

script.js
// Global scope
{
  var isNotPrivate = 1;
}

console.log(isNotPrivate); // 1

Then the global scope can access the isNotPrivate variable. That's because the isNotPrivate variable here was declared with var, and therefore it does completely ignore the block in which it is declared. And this is the reason why now, in modern JavaScript. Immediately Invoked Function Expressions are not that used anymore. Because if all we want is to create a new scope for data privacy, all we need to do, is to just create a block using letor const as we did above.

There's no need to create a function to create a new scope. Unless, of course, we want to use var for our variables. But we already know we probably shouldn't do that. Now on the other hand, if what you really need, is to execute a function just once, then the IIFE is still the way to go.