The “Module” pattern is based on closures and consists of two components: an outer function that defines a lexical environment, and a return set of inner functions that have access to this environment.
Let’s define the simplest module:
1 2 3 4 5 6 7 8 9 10 | let foo = ( function (){ let obj = {greeting: "hello" }; return { display: function (){ console.log(obj.greeting); } } })(); foo.display(); // hello |
The variable foo is defined here, which represents the result of the anonymous function. Inside such a function, an obj object is defined with some data.
The anonymous function itself returns an object that defines the display function. The returned object defines a public API through which we can access the data defined within the module.
1 2 3 4 5 | return { display: function (){ console.log(obj.greeting); } } |
This design allows you to close a certain set of data within the module function and mediate access to them through a specific API – returned internal functions.
Let’s look at a slightly more complex example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | let calculator = ( function (){ let data = {number: 0}; return { sum: function (n){ data.number += n; }, subtract: function (n){ data.number -= n; }, display: function (){ console.log( "Result: " , data.number); } } })(); calculator.sum(10); calculator.sum(3); calculator.display(); // result: 13 calculator.subtract(4); calculator.display(); // result: 9 |
This module is a primitive calculator that performs three operations: addition, subtraction, and output.
All data is encapsulated in a data object that stores the result of the operation. All operations are represented by three return functions: sum, subtract and display. Through these functions, we can control the result of the calculator from the outside.