ES6 module syntax

Time:2021-9-21

These are reading notes


1. Overview

Historically, JavaScript has never had a module system. It is impossible to split a large program into interdependent small files and assemble them in a simple way.
At the level of language standard, ES6 realizes module functions, and the implementation is quite simple. It can completely replace commonjs and AMD specifications and become a general module solution for browsers and servers.
The design idea of ES6 module is to be static as much as possible, so that the dependencies of the module and the input and output variables can be determined at compile time. Both commonjs and AMD modules can only determine these things at run time. For example, commonjs module is an object, and object properties must be found during input.

//Commonjs module
let { start, exits } = require('fs');

//Equivalent to
let _fs = require('fs');
let start = _fs.start;
let exits = _fs.exits;

The essence of the above code is to load the FS module as a whole (that is, all methods of loading FS), generate an object (_fs), and then read the methods from this object. This loading is called “runtime loading”, because this object can only be obtained at runtime, so there is no way to do “static optimization” at compile time.
ES6 module is not an object, but the output code is explicitly specified through the export command, and then input through the Import command.

//ES6 module
import { start, exists } from 'fs';

The essence of the above code is to load two methods from the FS module, and the other methods are not loaded. This loading is called “loading at compile time” or static loading, that is, ES6 can complete module loading at compile time, which is more efficient than the loading method of commonjs module. Of course, this also makes it impossible to reference the ES6 module itself because it is not an object.

2. Strict mode

The module of ES6 automatically adopts strict mode, whether you add “use strict” to the module header or not.
You should pay attention to the limitation of this (it is forbidden to point to global objects). In the ES6 module, the top-level this points to undefined, that is, this should not be used in the top-level code.

3. Export command

The module function is mainly composed of two commands: export and import. The export command is used to specify the external interface of the module, and the Import command is used to input the functions provided by other modules.
A module is a separate file. All variables inside the file cannot be obtained externally. If you want the external to be able to read a variable inside the module, you must use the export keyword to output the variable.

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';

The above code is the profile.js file, which saves the user information. ES6 regards it as a module, in which three variables are output externally with the export command.
There is another way to write export.

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
export { firstName, lastName };

It should be noted that the export command specifies the external interface and must establish a one-to-one correspondence with the variables inside the module.

//Error reporting
export 1;
//Error reporting
var m = 1;
export m;

The above two methods will report errors because no external interface is provided. The first writing method directly outputs 1, and the second writing method passes through variables,
, or output 1 directly. 1 is just a value, not an interface.

//Writing method I
export var m = 1;
//Writing method 2
var m = 1;
export {m};
//Writing method III
var n = 1;
export { n as m };

The above three methods are correct and specify the external interface m. Other scripts can get the value 1 through this interface. Their essence is to establish a one-to-one correspondence between the interface name and the internal variables of the module.
Similarly, the output of function and class must follow this writing method.

//Error reporting
function f() {}
export f;

//Right
export function f() {};

//Right
function f() {}
export {f};

In addition, the interface output by the export statement has a dynamic binding relationship with its corresponding value, that is, the real-time value inside the module can be obtained through this interface.

4. Import command

After using the export command to define the external interface of the module, other JS files can load the module through the Import command.
The Import command accepts a pair of braces that specify the variable names to be imported from other modules. The variable name in braces must be the same as the name of the external interface of the imported module.
The variables entered by the Import command are read-only, because its essence is the input interface, that is, it is not allowed to rewrite the interface in the script loading the module. However, if a variable is assigned to an object, an error will be reported if it is re assigned. It is allowed to rewrite the attribute of the variable.
Note that the Import command hasImprove effect, it will be lifted to the head of the whole module and executed first.

foo();
import { foo } from 'my_module';

The above code will not report an error, because the execution of import is earlier than the call of foo. The essence of this behavior is that the Import command is executed during the compilation phase, before the code runs.
Because import is executed statically, expressions and variables cannot be used, which can only get the syntax structure of the result at run time.

6. Export default command

When using the Import command, the user needs to know the variable name or function name to be loaded, otherwise it cannot be loaded.
In order to provide convenience for users to load modules without reading documents, you need to use the export default command to specify the default output for the template.

// export-dfault.js
export default function () {
    console.log('foo');
}

In the module file above, its default output is a function.
When other modules load the module, the Import command can specify any name for the anonymous function.

// import-default.js
import customName from './export-defalt';
customName(); // 'foo'

The Import command of the above code can point to the export-default.js output method with any name. At this time, you don’t need to know the function name output by the original module. It should be noted that curly braces are not used after the Import command.
The export default command can also be used before non anonymous functions.

// export-default.js
export default function foo () {
    console.log;
}

//Or write
function foo() {
    console.log('foo');
}
export default foo;

In the above code, the function name foo of foo function is invalid outside the module. When loading, it is regarded as anonymous function loading.

//Group 1
export default function crc32() { 
    // …
};
import crc32 from 'crc32'; //  input

//Group 2
export function crc32() {
    // …
};
import { crc32 } from 'crc32'; //  input

The above code is written in two groups. The first group is that when export default is used, the corresponding import statement does not need to use braces; The second group is the impractical export default. The corresponding import statement needs to use braces.
The export default command specifies the default output of the module. Obviously, a module can only have one default output, so the export default command can only be used once. Therefore, the Import command is not followed by the parenthesis, because it can only uniquely correspond to the export default command.
In essence, export default is to output a variable or method called default, and then the system allows you to give it any name. Therefore, the following writing is effective.

// modules.js
function add(x, y) {
    return x * y;
}
export { add as default};
//Equivalent to
// export default add;

// app.js
import { default as foo } from 'modules';
//Equivalent to
// import foo from 'modules';

Because the export default command only outputs a variable called default, it cannot be followed by a variable declaration statement.

//Right
export var a = 1;

//Right
var a = 1;
export default a;

//Error
export default var a = 1;

In the above code, export dafault a means to assign the value of variable a to variable default. Therefore, the last way of writing is wrong.
Similarly, because the essence of the export default command is to assign the following value to the default variable, you can write a value directly after export default.

//Right
export default 42;

//Error reporting
export 42;

In the above code, the error in the latter sentence is because the external interface is not specified, while the previous sentence specifies the external interface as default.

7. Compound writing of export and import

If the same module is input first and then output, the import statement can be written together with the export statement.

export { foo, bar } from 'my_module';
//It can be simply understood as
import { foo, bar } from 'my_module';
export { foo, bar };

In the above code, the export and import statements can be combined into one line. However, it should be noted that after writing a line, Foo and bar are not actually imported into the current module, but they are equivalent to forwarding these two interfaces to the outside world, so that the current module cannot directly use Foo and bar.
The interface name of the module and the overall output can also be written in this way.

//Interface renaming
export { foo as myFoo } from 'my_module';

//Overall output
export * from 'my_module';

The default interface is written as follows:

export { default } from 'foo';

The writing method of changing the named interface to the default interface is as follows.

export { es6 as default } from './someModule';
//Equivalent to
import { es6 } from './someModule';
export default es6;

Similarly, the default interface can be renamed a named interface.

export { default as es6 } from './someModule';

10、import()

The Import command will be statically analyzed by the JavaScript engine and executed before other statements in the module (the Import command is called “connect” Bing, which is actually more appropriate).

//Error reporting
if(x === 2) {
    import MyModual from './myModual';
}

In the above code, the engine processes the import statement during compilation, and will not analyze or execute the if statement at this time. Therefore, it is meaningless to put the import statement in the if code block, so it will report a syntax error instead of an execution error. That is, the import and export commands can only be at the top level of the module, not in the code block (for example, in the if code block or in the function).
Such a design is conducive to improving the efficiency of the compiler, but it also leads to the inability to load modules at run time. Syntactically, conditional loading is impossible. This creates an obstacle if the Import command replaces the require method of node. Because require is a runtime loading module, the Import command cannot replace the dynamic loading function of reqiure.

const path = './' + fileName;
const myModual = require(path);

The above statement is dynamic loading. Only the runtime knows which module to load. The Import command cannot do this.
The es2020 proposal introduces the import() function to support dynamic loading of modules.

import(specifier);

In the above code, the parameter specifier of the import function specifies the location of the module to be loaded. The import () function can accept whatever parameters the Import command can accept. The main difference between the two is that the latter is dynamic loading.
Import() returns a promise object.

const main = document.querySelector('mian');
import(`./section-modules/${someVariable}.js`).then(module => {
    module.loadPageInto(main);
    })
    .catch(err => {
        main.textContent = err.message;
    });

The import () function can be used anywhere, not only in modules, but also in non module scripts. It is specified by the runtime, that is, when it runs to this sentence, the specified module will be loaded. In addition, the import () function has no static connection with the loaded module, which is also different from the import statement. Import () is similar to the require method of node. The main difference is that the front end is asynchronous loading and the latter is synchronous loading.

Applicable scenario

Here are some applicable scenarios for import ().

1) Load on demand

Import () can load a module when necessary.

button.addEventListener('click', event => {
    import('./dialogBox.js')
    .then(dailogBox => {
        dialogBox.open();
    })
    .catch(error => {})
});

In the above code, the import () method is placed in the listener function of clicj event. This module will not be loaded until the user clicks the button.

2) Conditional loading

Import () can be placed in the if code block to load different modules according to different situations.

3) Dynamic module path

Import() allows module paths to be generated dynamically.

Attention
After import () loads the module successfully, the module will be used as an object and as a parameter of the then method. Therefore, the syntax of object deconstruction assignment can be used to obtain the output interface.

import('./myModule.js')
.then(({expor1, export2}) => {});

If you want to load multiple modules at the same time, you can use the following writing method.

Promise.all([
    import('./module1.js'),
    import('./module2.js'),
])
.then(([module1, module2]) => {});

Import () can also be used in async functions.

async function mian() {
    const myModule = await import('./myModule.js');
    const {export1, export2} = awair import('./myModule.js');

main();

Recommended Today

Seven Python code review tools recommended

althoughPythonLanguage is one of the most flexible development languages at present, but developers often abuse its flexibility and even violate relevant standards. So PythoncodeThe following common quality problems often occur: Some unused modules have been imported Function is missing arguments in various calls The appropriate format indentation is missing Missing appropriate spaces before and after […]