- Modern JavaScript Web Development Cookbook
- Federico Kereki
- 468字
- 2021-07-02 14:49:59
Doing modules the IIFE way
Before modules became widely available, there was a fairly common pattern in use, which basically provided the same features that today's modules do. First, let's introduce a sample fragment of code, and then examine its properties:
// Source file: src/iife_counter.js
/* @flow */
/*
In the following code, the only thing that needs
an explicit type declaration for Flow, is "name".
Flow can work out on its own the rest of the types.
*/
const myCounter = ((name: string) => {
let count = 0;
const inc = () => ++count;
const get = () => count; // private
const toString = () => `${name}: ${get()}`;
return {
inc,
toString
};
})("Clicks");
console.log(myCounter); // an object, with methods inc and toString
myCounter.inc(); // 1
myCounter.inc(); // 2
myCounter.inc(); // 3
myCounter.toString(); // "Clicks: 3"
Defining a function and immediately calling it is called an IIFE, pronounced iffy, and stands for Immediately Invoked Function Expression.
We defined a function (the one starting with name => ...), but we immediately called it (with ("Clicks") afterwards). Therefore, what gets assigned to myCounter is not a function, but its returned value, that is, an object. Let's analyze this object's contents. Because of the scoping rules for functions, whatever you define inside isn't visible from the outside. In our particular case, this means that count, get(), inc(), and toString() won't be accessible. However, since our IIFE returns an object including the two latter functions, those two (and only those two) are usable from the outside: this is called the revealing module pattern.
If you have followed on so far, the following should be clear to you:
- Whatever variables or functions are defined in the module aren't visible or accessible from the outside, unless you voluntarily reveal them
- Whatever names you decide to use in your module won't conflict with outside names because of normal lexical scoping rules
- The captured variables (in our case, name) persist so that the module can store information and use it later
All in all, we must agree that IIFEs are a poor man's module and their usage is quite common. Browse the web for a bit; you are certain to find examples of it. However, ES6 introduced a more general (and clearer and easier to understand) way of defining modules, which is what we'll be using: let's talk about this next.