Deep understanding of ES6 modules

Time:2020-5-22

Learn more about ES6 modules

At present, almost all of our projects are developed based on Web pack, roll up and other construction tools, and modularity is the norm.

We are not new to it. Today, we will review the module mechanism of ES6 systematically, and summarize the commonly used operations and best practices, hoping to help you.

Some simple background

It’s a mechanism we all want to implement.

The same is true in JavaScript. A large JavaScript program is divided into different parts. If you want to use any part, you can take that part.

For a long time, nodejs has such capabilities. Later, more and more libraries and frameworks have modular capabilities, such as commonjs, amd based implementation (such as requirejs), and subsequent webpack, Babel, etc.

By 2015, a standard modular system was born, which is the protagonist of today’s ES6 model system.

At a glance, it is not difficult to find that the model system of ES6 is very similar to the commonjs syntax. After all, the model system of ES6 has come from the era of commonjs and is deeply influenced by commonjs.

Take a simple example, for example, in commonjs:( https://flaviocopes.com/commo…

//file.js
module.exports = value;

//Introduce value
const value = require('file.js')

In ES6:

// const.js
export const value = 'xxx';


import { value } from 'const.js'

The grammar is very similar.

Let’s take a look at import and export and several related features to learn more about ES6 modules.

Benefits of modularity

The benefits of modularity are mainly two points:

1. Avoid global variable pollution
2. Handle dependency effectively

With the evolution of the times, browser native also began to support ES6 import and export syntax.

Deep understanding of ES6 modules

Let’s start with a simple example:

<script type="module">
  import { addTextToBody } from '/util.js';

  addTextToBody('Modules are pretty cool.');
</script>

// util.js 
export function addTextToBody(text) {
  const div = document.createElement('div');
  div.textContent = text;
  document.body.appendChild(div);
}

If you want to handle events, the same is true. Here is a simple example:


<button id="test">Show Message</button>
<script type="module" crossorigin></script>

// showImport.js
import { showMessage } from '/show.js'

document.getElementById('test').onclick = function() {
  showMessage();
}

// show.js
export function showMessage() {
  alert("Hello World!")
}

If you want to run this demo, pay attention to a simple service:

$ http-server

Otherwise, you will see a CORS throw wrong.

As for the specific reasons and other details of the mistake, it is not the focus of this article, and you can read the following links for details.

https://jakearchibald.com/201…

Strict mode

https://developer.mozilla.org…

‘use strict’ declaration is not new to us. It is often used in the era of Es5. It is usually added at the top of the file to disable the unfriendly part of JavaScript, which helps us write more rigorous code.

This feature is enabled by default in ES6 syntax. If there is less strict code in the code, an error will be reported, for example:

Deep understanding of ES6 modules

Here are some of my excerpts from MDNStrict modeMiddle quiltDisablePart of:

  • Variables can’t be left undeclared
  • Function parameters must have unique names (or are considered syntax errors)
  • with is forbidden
  • Errors are thrown on assignment to read-only properties
  • Octal numbers like 00840 are syntax errors
  • Attempts to delete undeletable properties throw an error
  • delete prop is a syntax error, instead of assuming delete global[prop]
  • eval doesn’t introduce new variables into its surrounding scope
  • eval and arguments can’t be bound or assigned to
  • arguments doesn’t magically track changes to method parameters
  • arguments.callee throws a TypeError, no longer supported
  • arguments.caller throws a TypeError, no longer supported
  • Context passed as this in method invocations is not “boxed” (forced) into becoming an Object
  • No longer able to use fn.caller and fn.arguments to access the JavaScript stack
  • Reserved words (e.g protected, static, interface, etc) cannot be bound

Several uses of exports

ES6 module only supports static export. You can only use export in the outermost scope of the module, not in conditional statements or function scopes.

From the perspective of classification, there are three main types of exports:

  1. Named Exports (Zero or more exports per module)
  2. Default Exports (One per module)
  3. Hybrid Exports

Exports overview:

// Exporting individual features
export let name1, name2, …, nameN; // also var, const
export let name1 = …, name2 = …, …, nameN; // also var, const
export function functionName(){...}
export class ClassName {...}

// Export list
export { name1, name2, …, nameN };

// Renaming exports
export { variable1 as name1, variable2 as name2, …, nameN };

// Exporting destructured assignments with renaming
export const { name1, name2: bar } = o;

// Default exports
export default expression;
export default function (…) { … } // also class, function*
export default function name1(…) { … } // also class, function*
export { name1 as default, … };

// Aggregating modules
export * from …; // does not set the default export
export * as name1 from …;
export { name1, name2, …, nameN } from …;
export { import1 as name1, import2 as name2, …, nameN } from …;
export { default } from …;

Let me introduce the common usage of exports.

1. Named exports (export each function / variable)

Named export, this way to export multiple functions, generally using scenarios such as utils, tools, common and other tool class function sets, or all site unified variables.

You just need to prefix the variable or functionexportKey words.

//------ lib.js ------
export const sqrt = Math.sqrt;

export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------  main.js  Usage 1------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

//------  main.js  Usage 2------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

We can also export a list directly, such as the above lib.js It can be rewritten as:

//------ lib.js ------
const sqrt = Math.sqrt;
function square(x) {
    return x * x;
}
function add (x, y) {
    return x + y;
}
export { sqrt, square, add }

2. Default exports (export a default function / class)

This method is relatively simple, and is generally used for a class file or a function file with a single function.

There can only be one export default output in a module.

There are two main differences between export default and export:

You do not need to know the specific variable name of the export. You do not need {} when importing

//------ myFunc.js ------
export default function () {};

//------ main.js ------
import myFunc from 'myFunc';
myFunc();

Export a class

//------ MyClass.js ------
class MyClass{}

export default MyClass;

//------ Main.js ------
import MyClass from 'MyClass';

Note that {} is not required for the default export.

3. Mixed exports

Mixed export, that is, the combination of the first and second points above. For example, lodash is a common combination.

//------ lib.js ------
export var myVar = ...;
export let myVar = ...;
export const MY_CONST = ...;

export function myFunc() {
  // ...
}
export function* myGeneratorFunc() {
  // ...
}
export default class MyClass {
  // ...
}

// ------ main.js ------
import MyClass, { myFunc } from 'lib';

Another example is lodash:

//------ lodash.js ------
export default function (obj) {
  // ...
};
export function each(obj, iterator, context) {
  // ...
}
export { each as forEach };

//------ main.js ------
import _, { forEach } from 'lodash';

4. Re exporting

In general, the export output variable is the name defined in the original file, but you can also use the as keyword to specify the alias, which is generally used to simplify or semantize the function name of export.

//------ lib.js ------
export function getUserName(){
  // ...
};
export function setName(){
  // ...
};

//Output alias. When importing, you can use both the original function name and alias
export {
  Getname as get, // allow to output twice with different names
  getName as getNameV2,
  setName as set
}

5. Module redirects

Sometimes, in order to avoid importing too many modules into the upper module, we may use the lower module as a transit, and directly export the contents of another module as follows:

//------ myFunc.js ------
export default function() {...};
 
//------ lib.js ------
export * from 'myFunc';
export function each() {...};
 
//------ main.js ------
import myFunc, { each } from 'lib';

Export only supports static export at the outermost layer, only export variables, functions and classes. The following usages are wrong.

`Export usage of error:

//Value of direct output variable
export 'Mark';

//Brackets are not used or default is not added
//If there is only one export number, you need to add default, or use brackets
var name = 'Mark';
export name;

//Export does not output variables within the scope of a block
function () {
  var name = 'Mark';
  export  { name };
}

Several uses of import

The usage of import corresponds to that of export one by one, but import supports static import and dynamic import. Dynamic import supports later and has poor compatibility.

Deep understanding of ES6 modules

Let me summarize the basic usage of import:

1. Import All things

When there are multiple functions or variables in export, such as the first point in the article, you can use the * as keyword to export all functions and variables, and the name followed by as is the namespace of the module.

//Export all functions and variables of Lib
import * as lib from 'lib';

//Call with lib as namespace, similar to object
console.log(lib.square(11)); // 121

2. Import a single/multiple export from a module

Import single or multiple functions from the module file. Different from * as namepage, this is an on-demand import. Here is an example:

//Import square and Diag functions
import { square, diag } from 'lib';

//Import only one function of square
import { square } from 'lib';

//Import default module
import _ from 'lodash';

//Import default module和单个函数,这样做主要是简化单个函数的调用
import _, { each } from 'lodash';

3. Rename multiple exports during import

Like export, you can also use as keyword to set alias. When the names of two classes of import are the same, you can use as to reset the names of import modules, or you can use as to simplify the names.
For example:

//Simplify function names with as
import {
  reallyReallyLongModuleExportName as shortName,
  anotherLongModuleName as short
} from '/modules/my-module.js';

//Avoid duplicate names
import { lib as UserLib} from "alib";
import { lib as GlobalLib } from "blib";

4. Import a module for its side effects only

Sometimes we just want to import a module, such as a style, or a class library.

//Import styles
import './index.less';

//Import class library
import 'lodash';

5. Dynamic Imports

Static import will download all module resources at the first load

In our actual development, sometimes we need dynamic import.

For example, click a tab to load some new modules:

//When dynamic import, a promise is returned
import('lodash')
  .then((lodash) => {
    // Do something with lodash.
  });

//The above sentence is actually equivalent to
const lodash = await import('lodash');

New usage of ES7:

async function run() {
    const myModule = await import('./myModule.js');

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

    const [module1, module2, module3] =
        await Promise.all([
            import('./module1.js'),
            import('./module2.js'),
            import('./module3.js'),
        ]);
}

run();

summary

Above, I summarized the simple background and common import and export usage of ES6 module, but this is far from all of it, and the space is limited. If you want to learn more, you can see the following extended reading part (the quality is good, you can see it).

last

If you think the content is helpful, you can focus on my official account, “front-end e”, and learn the latest information, learn together and grow together!

Deep understanding of ES6 modules

Extended reading:

ECMAScript 6 modules: the final syntax

JavaScript modules

dynamic-import

If you don’t understand the require and import in node, you will be hit hard

https://www.zhangxinxu.com/wordpress/2018/08/browser-native-es6-export-import-module/

Recommended Today

IView, upload component beforeupload compress image

critical code <Upload multiple :format=”[‘jpg’,’jpeg’,’png’]” :beforeUpload=”beforeUpload” action=”” :on-success=”upload” > < button icon = “IOS cloud upload outline” > upload picture < / button > </Upload> import Compressor from “compressorjs” beforeUpload(file) { return new Promise((resolve, reject) => { let isLt1M = file.size / 1024 / 1024 < 1; if (isLt1M) { resolve(file); } new Compressor(file, { […]