The best definition I've ever seen about ES modules is: "modules allow us to import and export stuff". Exactly! We use modules for import/export components, classes, help methods, variables and other stuff. They help us to organize our code.
In fact Module is one of the popular design pattern that allows encapsulate the code. Let's look at the implementation of this pattern.
constModule=(function(){let_privateVariable;letpublicVariable;function_privateMethod(){}functionpublicMethod(){}return{publicVariable,publicMethod,};})();
We have there ananonymous closure
that creates anenclosed scope
withprivate
andpublic
methods / variables and asingleton object
that get us an access to the public properties of the module.
Now let’s look at ES modules. Imagine, we have some modules...
// module Aconsole.log(‘a’)
// module Bconsole.log(‘b’)
// module Cconsole.log(‘c’)
Modules first!
When we import these modules into a file and execute it, the modules will beinvoked
first.
import*asafrom‘./a.js’import*asbfrom‘./b.js’import*ascfrom‘./c.js’console.log(‘index’);
Output:
abcindex
Modules are evaluated only once!
The module will be evaluated only once and it does not matter how many files are module dependent.
// module Aimport*ascfrom‘./c.js’console.log(‘a’)
// module Bimport*ascfrom‘./c.js’console.log(‘b’)
import*asafrom‘./a.js’import*asbfrom‘./b.js’console.log(index);
Output:
cabindex
It works thanks toModule Map
. When a module is imported, amodule record
is created and placed in the Module Map. When another module try to import this module, the module loader will look up in the Module Map first. Thus we can have asingle
instance of each module.
Another demonstration of this idea.
// module Aimport*asbfrom‘./b.js’console.log(‘a’)
// module Bimport*asafrom‘./a.js’console.log(‘b’)
import*asafrom‘./a.js’import*asbfrom‘./b.js’console.log(index);
Output:
baindex
The module loading process takes several steps:
Parsing
- if there are any errors in your module, you will know about it firstLoading
- if there are any imports in your module, they will be recursively imported (and themodule graph
will be built).Linking
- creating a module scopeRun time
- running a module body
So, let’s look at our previous example step by step.
->import*asafrom'./a.js'|->creatingamodulerecordforfile'./a.js'intotheModulemap|->parsing|->loading-import*asbfrom'./b.js'|->creatingamodulerecordforfile'./b.js'intotheModulemap|->parsing|->loading->import*asafrom'./a.js'|->amodulerecordforfile'./a.js'alreadyexistintheModuleMap|->linked|->run|->linked|->run
This case is an example of thecircular module dependency
. And if we try to call some variable from the A module in the B module, we will get a Reference Error in this case.
Module properties are exported by reference!
Let’s add a public variable into the A module.
// module Aexportletvalue=1;exportfunctionsetValue(val){value=val;}
Now let’s import the A module into the B module...
// module Bimport*asafrom‘./a.js’a.setValue(2);
...and look at the value from the C module.
// module Cimport*asafrom‘./a.js’console.log(a.value);
Output will be '2'. Pay attention to one remarkable feature of the module - we cannot directly change the value property in module B. The 'value' property isread-only
, and we get a TypeError.
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse