The target

By reading this article you can learn:

  • Some writing of the original simulation module

  • CommonJS specification

  • AMD specification

  • CMD specification

  • The difference between AMD and CMD

  • ES6 Modules specification

  • Differences between CommonJS and ES6 Modules specifications

Modular primitive notation

In the absence of CommonJS and ES6, there are three possible ways to achieve modularity:

1. A function is a module

<script>  
  function m1 () {  
    // ...  
  }  
  function m2 () {  
    // ...  
  }  
</script>  
Copy the code

Disadvantages: contamination of global variables, no guarantee against collisions with other modules, and no direct relationship between module members.

2. An object is a module

Object writing To address this shortcoming, you can write a module as an object into which all module members are placed.

index.html

<script>  
  var module1 = new Object({  
    _sum: 0,  
    foo1: function () {},  
    foo2: function () {}  
  })  
</script>  
Copy the code

Disadvantages: all module members are exposed, and internal state can be overwritten.

For example, if we only wanted to expose two methods without exposing _sum, we would not be able to do so.

In this case, _sum may be overwritten externally:

module1._sum = 2;
Copy the code

3. Execute the function as a module immediately

<script>  
  var module1 = (function({  
    var _sum = 0;  
    var foo1 = function ({};  
    var foo2 = function ({};  
    return {  
      foo1: foo1,  
      foo2: foo2  
    }  
  })();  
</script>  
Copy the code

Module functionality is implemented using scoped closures within the immediate function, exporting the members we want to export.

External code cannot read _sum:

console.log(module1._sum) // undefined  
Copy the code

CommonJS specification

There is no specific introduction here, I just give some important knowledge points and confusion points.

Mainly from the following four aspects:

  • Exposed to the module

  • Refer to the module

  • Module identifier

  • CommonJS specification features

1. Expose (define) modules

Proper exposure:

Modules can be exposed in two ways:

  • module.exports = {}

  • exports.xxx = 'xxx'

For example, if you have a m1.js file:

The first type of exposure:

module.exports = {  
    name'lindaidai'.sex'boy'  
}  
Copy the code

The second type of exposure:

exports.name = 'lindaidai';  
exports.sex = 'boy'  
Copy the code

Why is it possible to write these two ways?

The module variable represents the entire module, namely m1.js. The module variable has an exports attribute, which is a reference to the exports variable.

var exports = {};  
var module = {  
    exports: exports  
}  
return module.exports  
Copy the code

(Of course, this is just pseudo code, in fact, you will find no effect.)

Module. exports, not exports, ended up exporting.

Confusing ways of exposure:

If you tried exports = {name: ‘lindaidai’} in your code, you would find that you didn’t get the name attribute at all where it was introduced.

// m1.js  

exports = {  
    name'lindaidai'  
}

Copy the code
// test.js

const math = require('./m1.js')    
console.log(m1); / / {}

Copy the code

Execute Node test.js on the console and find m1 printed out as an empty object.

Exports depend on module.exports. If you re-assign the entire exports object to module. Exports and module.exports are not the same object because they refer to different reference addresses:

module.exports -> {} // Point to an empty object
exports -> { name'lindaidai' } // It points to another object

Copy the code

Exports = {} does not affect module.exports.

Let’s take a look at some true and false examples:

// m1.js

/ / 1. Correct
module.exports = {  
    name'lindaidai'.sex'boy'  
}  
  
/ / 2. Correct
exports.name = 'lindaidai';  
exports.sex = 'boy'  
  
/ / 3. Correct
module.exports.name = 'lindaidai';  
module.exports.sex = 'boy'  
  
/ / 4. Invalid
exports = {  
    name'lindaidai'.sex'boy'  
}  
Copy the code

You can see

  • Exports. name = XXX is an abbreviation of module. Exports. name = XXX.

  • Exports = {} is not an abbreviation of module.exports = {}.

2. Reference (import) modules

For module references, use the global method require().

Note that the ⚠️ global method is a node method, not a window method, so you can’t use it in HTML without doing anything:

index.html:

<body>  
    <script>  
        var m1 = require('./m1.js')  
        console.log(m1);  
    </script>  
</body>  
Copy the code

For example, the above 👆 so that you open the page console must be an error:

Uncaught ReferenceError: require is not defined  
	at index.html:11  
Copy the code

This works if you are referencing node test.js in another JS file (such as test.js) and executing node test.js on a terminal:

test.js:

var m1 = require('./m1.js')  
  
console.log(m1);  

Copy the code

That’s because you have Node.js installed globally on your computer, so you can play this way.

So we can see thatrequire()It is aNode.jsIs not unique to CommonJS, which is just one of many specifications.

This specification allows us to:

  • Exports = {} or exports.name = XXX

  • Introduce modules using const m1 = require(‘./m1’)

Note ⚠ ️ :

Another important point is that the require() argument even allows you to be an expression.

That is, you can set it to a variable:

test.js:

var m1Url = './m1.js';  
var m1 = require(m1Url);  
  
// Even do some string concatenation:
var m1 = require('./m' + '1.js');  
Copy the code

3. Module identifier (IDENTIFIER)

The module identifier is essentially the argument to which you call require() when importing a module.

You’ll see a lot of usage like this:

// Import directly
const path = require('path');  
// Relative path
const m1 = require('./m1.js');  
// Import directly
const lodash = require('lodash');  
Copy the code

This is because the modules we introduce have different categories, such as path, which comes with Node.js, M1, which is a path module, and lodash, which we download to node_modules using NPM I lodash.

It is divided into the following three types:

  • Core modules (node.js built-in modules)

  • Path module (module that starts relative or absolute location)

  • Custom modules (modules in node_modules)

There are three ways to find modules:

  • Core module, directly skip path analysis and file location

  • Path module, directly derive the relative path is good

  • For a custom module, first look for the module in the current directory node_modules. If there is no module, it will look up one level of the directory, node_modules, and then up until there is no module in the root directory, and then throw an error.

The search procedure for a custom module:

This process is actually called path analysis.

Now I’m going to change the test.js:

// var m1 = require('./m1.js');  
  
// console.log(m1);  
console.log(module.paths)  
Copy the code

Then execute on terminal:

node test.js

You’ll find the following array printed:

LinDaiDaideMBP:commonJS lindaidai$ node test.js  
[  
  '/ Users/lindaidai/codes/test/CommonJS and ES6 / CommonJS/node_modules'.'/ Users/lindaidai/codes/test/CommonJS and ES6 / node_modules'.'/Users/lindaidai/codes/test/node_modules'.'/Users/lindaidai/codes/node_modules'.'/Users/lindaidai/node_modules'.'/Users/node_modules'.'/node_modules'  
]  
Copy the code

When I say find, I mean find the module you’re using, I’m using test.js, and you probably won’t see anything. Now let’s simulate the functionality of a custom module we installed using NPM I.

First, I created a new folder called node_modules in the root directory and created a new file called lindaidai.js to simulate an NPM installation dependency.

Directory structure:

Write lindaidai.js a little:

module.exports = {  
  printfunction ({  
    console.log('lindaidai')}}console.log('Lindaidai module:'.module.paths)  
Copy the code

Then introduce the lindaidai module in test.js:

// var m1 = require('./m1.js');  
// console.log(m1);  
// console.log(module.paths)  
  
var lindaidai = require('lindaidai');  
lindaidai.print();  
Copy the code

Now execute Node test.js and you’ll see output:

LinDaiDaideMBP:commonJS Lindaidai $node test.js Lindaidai: ['/ Users/lindaidai/codes/test/CommonJS and ES6 / CommonJS/node_modules'.'/ Users/lindaidai/codes/test/CommonJS and ES6 / node_modules'.'/Users/lindaidai/codes/test/node_modules'.'/Users/lindaidai/codes/node_modules'.'/Users/lindaidai/node_modules'.'/Users/node_modules'.'/node_modules'  
]  
lindaidai  
Copy the code

So now you can see what the usual lookup order is when we use this dependency, which is the order in which the custom modules are searched.

File location:

👆 has already introduced the path analysis above, but there is still a problem, is that we import the module its suffix (extension) can be omitted, so how does Node know whether we import a JS or a JSON? This is where file location comes in.

If a directory is passed in, NodeJS treats it as a package and determines the file name in the following way

The first step is to find package.json in the directory and parse the main field with json.parse ()

Second, if the file specified by the main field still omitted the extension, the.js,.node, and.json attempts will be added successively.

Third, if the file specified by the main field does not exist, or does not exist at all, the index.js, index.node, and index.json files in this directory will be loaded by default.

The above is the process of file location, and then with the process of path analysis, permutation and combination, how many possible ah. Therefore, the introduction of custom modules is the most expensive performance.

(source: summarize zhuanlan.zhihu.com/p/27644026)

4. Characteristics of CommonJS specification

Let me list some of the CommonJS specification features first, and then we’ll look at the examples bit by bit.

  • All code runs in the module scope and does not pollute the global scope;

  • The module is synchronously loaded, that is, only after the loading is complete, the following operations can be performed;

  • The module is cached after the first execution, and only returns cached results if it is reloaded. If it wants to execute again, the cache can be cleared.

  • CommonJS output is a copy of the value (that is, the value returned by require is a copy of the value being output, and changes within the module do not affect this value).

(Summary source: juejin.cn/post/684490…)

The first point is easy to understand, an important function of our module is not this.

The second point is synchronous loading. Let’s write an example to verify this

Synchronous loading cases:

m1.js:

console.log('I am module M1')  
module.exports = {  
    name'lindaidai'.sex'boy'  
}  
Copy the code

test.js

var m1 = require('./m1');  
console.log('I'm the Test module');  
Copy the code

As you can see, the test module is dependent on M1 and was downloaded first from M1, so if I execute Node test.js, I will get the following result:

LinDaiDaideMBP:commonJS Lindaidai $node test.jstestThe moduleCopy the code

This verifies that modules are loaded synchronously in CommonJS, i.e., they cannot be performed until they are loaded.

The third point is that the module will be cached after the first execution. We can also write an example to verify this.

The module caches cases after first execution:

m1.js:

var name = 'lindaidai';  
var sex = 'boy';  
  
exports.name = name;  
exports.sex = sex;  
Copy the code

test.js:

var m1 = require('./m1');  
m1.sex = 'girl';  
console.log(m1);  
  
var m2 = require('./m1');  
console.log(m2);  
Copy the code

Test also depends on m1, but I import M1 twice. The first time I import m1, I change the value of m1.sex, and the second time I import M2, but m1 and m2 are the same:

LinDaiDaideMBP:commonJS lindaidai$ node test.js  
{ name: 'lindaidai', sex: 'girl' }  
{ name: 'lindaidai', sex: 'girl' }  
Copy the code

This means that the module is cached after the first execution and only returns the cached result when it is reloaded. Here I have changed the value of m1.sex to prove that it actually fetched the cached result.

If you change the sex property of m1 module, then m2 will get the changed value the second time.

Well… I’m trying to prove it. Because the fourth feature of CommonJS can be a good solution to your question.

4. CommonJS output is a copy of the value, that is, you import modules with require(), but how you change them in the latest module does not affect modules you already require(). Let’s look at an example.

CommonJS output is a copy of a value:

m1.js:

var name = 'lindaidai';  
var sex = 'boy';  
var advantage = ['handsome']  
  
setTimeout(function ({  
  sex = 'girl';  
  advantage.push('cute');  
}, 500)  
  
exports.name = name;  
exports.sex = sex;  
exports.advantage = advantage;  
Copy the code

test.js:

var m1 = require('./m1');  
setTimeout(function ({  
  console.log('read count after 1000ms in commonjs is', m1.sex)  
  console.log('read count after 1000ms in commonjs is', m1.advantage)  
}, 1000)  
Copy the code

The result of executing Node test.js is:

LinDaiDaideMBP:commonJS lindaidai$ node test.js  
read count after 1000ms in commonjs is boy  
read count after 1000ms in commonjs is [ 'handsome'.'cute' ]  
Copy the code

Var m1 = require(‘./m1’) var m1 = require(‘./m1’) = require(‘./m1’) However, the Advantage reference type still shares the same memory address. (This kind of replication relationship reminds me of the previous prototype chain inheritance, which also affects the reference type in Father. Prototype.)

Note In fact, the copy here refers to the shallow copy of JavaScript. If you have any questions about the deep copy of JavaScript, you can refer to the shallow copy and deep copy of JavaScript

If you write this here:

m1.js:

var name = 'lindaidai';  
var sex = 'boy';  
var advantage = ['handsome']  
  
setTimeout(function ({  
  sex = 'girl';  
  // advantage.push('cute');  
  advantage = ['cute'];  
}, 500)  
  
exports.name = name;  
exports.sex = sex;  
exports.advantage = advantage;  
Copy the code

Now the result must be:

LinDaiDaideMBP:commonJS lindaidai$ node test.js  
read count after 1000ms in commonjs is boy  
read count after 1000ms in commonjs is [ 'handsome' ]  
Copy the code

Because you’re reassigning advantage to M1.

Of course, if you return a function in m1.js, you can get the changed value in test.js, as in this example:

var counter = 3;  
function incCounter({  
  counter++;  
}  
module.exports = {  
  get counter() {  
    return counter  
  },  
  incCounter: incCounter,  
};  
Copy the code

Because you’re actually forming a closure here, and the counter property is a valuer function.

CommonJS output is a copy of a value. This is a bit ambiguous for variables of reference type, such as the advantage example above.

AMD specification

1. Causes

The CommonJS specification looks pretty good, so why else? AMD, CMD, how do they relate to CommonJS?

We know that the concept of modularity applies not only to the server side, but also to the client side.

The CommonJS specification is not suitable for use in client-side (browser) environments, as in the example above:

test.js:

const m1 = require('./m1.js')  
console.log(m1);  
  
// Some code unrelated to the M1 module
function other ({}  
other();  
Copy the code

How does this code work in a browser environment?

  • First load m1.js

  • Wait for m1.js to finish loading before executing the following content

This is already mentioned in the CommonJS specification features.

The rest of the content will wait for M1 to load. What if M1 loads slowly? That creates a lag, which is definitely not client-friendly. This case of waiting for the last one to finish loading is called “synchronous loading”. Obviously, we prefer that the execution of other() does not wait for M1 to finish loading, so we want M1 to be “asynchronous loading”, which is AMD.

Before introducing AMD, let’s look at the differences between the CommonJS specification for the server side and the browser. It helps you understand why CommonJS is not a good fit for the client side:

  • All modules on the server are stored on the local hard disk and can be loaded synchronously. The waiting time is the read time of the hard disk.

  • The browser, all the modules are on the server side, the wait time depends on the speed of the network, it can be a long time, the browser is in suspended animation.

2. Define and expose modules

With this background, we know that AMD was created in large part to allow us to load modules asynchronously.

So now let’s have a look at its introduction.

AMD stands for Asynchronous Module Definition. (The previous A is easy to remember, it reminds me of the async modifier that defines asynchronous functions.)

It loads modules asynchronously without affecting the execution of subsequent statements. All statements that depend on this module are defined in a callback function that will not run until the load is complete.

This is where we need another important way to define our module: define().

It actually takes three parameters:

define(id? , dependencies? , factory)

  • Id: a string that represents the name of the module, but is optional

  • Dependencies: An array of optional paths to which the module you define depends

  • Factory: factory method, a function, which is the concrete module content

Pit one:

So there’s actually a problem, because I read so many books, but when I tried to write a case, I thought I could use define just like require, but the console kept saying something wrong:

ReferenceError: define is not defined

Node.js is not a built-in node.js method, but you need to use the JavaScript library to use it.

Currently, there are two major Javascript libraries that implement the AMD specification: require.js and curl.

I acid…

Let’s go to the requirejs website to see how to use it. Since my examples are in the Node execution environment, I used NPM install to download it:

I created a new folder called AMD as an example of AMD.

Execute in the root directory of the project:

npm i requirejs

(I looked around NPM, but I didn’t see anything that could be remotely introduced using CDN.)

After execution, the dependency package appears in the root directory of the project, opened to look, indeed downloaded down:

Now you can happily use define() in your project 😊.

For a small example, I’ve redefined a math.js:

math.js

define(function ({  
  var add = function (a, b{  
    return a + b;  
  }  
  return {  
    add: add  
  }  
})  
Copy the code

Here the module is simple, deriving an addition function.

Why do you write “add: add” instead of just “add”? Don’t forget that the abbreviation for this object’s namesake property is an ES6 invention.

3. Reference modules

Pit 2:

OK👌, now that the module can be exported, let’s see how to reference it. Following the textbook, I introduced the math module in test.js and wanted to call the add() method:

test.js:

require(['math'].function(math{  
  console.log(math)  
  console.log(math.add(1.2));  
})  
Copy the code

Then execute node test.js skillfully.

I acid…

Another error, damn…

throw new ERR_INVALID_ARG_TYPE(name, 'string', value);  
 TypeError [ERR_INVALID_ARG_TYPE]: The "id" argument must be of type string. Received an instance of Array  
Copy the code

The first argument is the array of modules to load, and the second argument is the callback after loading.

Ill 😣… 👆require([modules], callback) is just a gimmick like define, and if you do use it at all, use JavaScript library methods.

Since requirejs is already installed, I can use it directly. Now I have modified the test.js file:

var requirejs = require("requirejs"); // Introduce the requirejs module
  
requirejs(['math'].function(math{  
  console.log(math)  
  console.log(math.add(1.2));  
})  
Copy the code

Ok, now you can use node test.js normally…

I feel bad… Feeling obviously is already very common some familiar knowledge, really want to use when the discovery and a lot of teaching materials say is not so one and the same… I also hope that after reading some textbooks, it is best to practice it in person, because I am also a blogger, so I know that sometimes some knowledge points may also be from other people’s articles but not through practice, so it is best to move their own hands)

4. Depend on the define of other modules

You can see define has two other parameters, the first is the name of the module, nothing to talk about, let’s look at the second module that it depends on.

Remember back in the CommonJS specification we wrote a m1.js? Now let’s take this module and use it as a dependency in math.js.

m1.js:

console.log('I'm M1, I'm loaded... ')  
module.exports = {  
    name'lindaidai'.sex'boy'  
}  
Copy the code

Then modify math.js:

math.js:

define(['m1'].function (m1{  
  console.log('I'm Math, I'm loaded... ')  
  var add = function (a, b{  
    return a + b;  
  }  
  var print = function ({  
    console.log(m1.name)  
  }  
  return {  
    add: add,  
    print: print  
  }  
})  
Copy the code

Test.js = test.js = test.js

var requirejs = require("requirejs"); // Introduce the requirejs module
  
requirejs(['math'].function(math{  
  console.log('I'm test, I'm loaded... ')  
  console.log(math.add(1.2));  
  math.print();  
})  
function other ({  
  console.log('I'm in the Test module, but I don't rely on Math')}; other();Copy the code

So we can see that the dependencies are:

test -> math -> m1

If, according to the AMD specification, the module is loaded only after the previous module is loaded, then we can imagine that when I enter node test.js on the terminal, the result should be:

LinDaiDaideMBP:commonJS Lindaidai $node test.jstestModule, but I don't rely on math. I'm M1. I'm loaded... I'm Math, I'm loaded... I am atest, I was loaded... 3 lindaidaiCopy the code

(This, I believe that we should see the dependence of each other 😢)

But the reality is always so cruel, when I press enter, and the error…

Acid again…

ReferenceError: module is not defined

This error is reported in m1.js… It took a few seconds to react…

Since it is the use of AMD specification, that we must be unified in the end, M1. Js used or CommonJS specification, of course not.

OK, let’s modify m1.js:

m1.js:

define(function ({  
  console.log('I'm M1, I'm loaded... ')  
  return {  
    name'lindaidai'.sex'boy'}})Copy the code

OK👌, this time there is no problem, according to our expectations to execute… 😊.

As FAR as I know, requirejs can also be used to reference and define the main module of a web application in a script. Take a look:

www.ruanyifeng.com/blog/2012/1…

I’ll make a list of some of the differences at the end, but let’s take a look at CMD first.

CMD specification

CMD (Common Module Definition) is the seaJS recommended specification. It relies on the proximity and requires when used.

Take a look at this code to get a sense of how it works:

define(function(require, exports, module{  
  var math = require('./math');  
  math.print()  
})  
Copy the code

The parameters for define() are even the same:

define(id? , dependencies? , factory)

But what is the difference? Let’s look at the last factory parameter.

The factory function takes three arguments:

  • require

  • exports

  • module

    CommonJS, CommonJS, CommonJS

  • Require: Introduces a module

  • Exports: exports of the current module, also known as module.exports

  • Module: Indicates the current module

Now let’s talk about the difference between AMD and CMD.

Although they all take the same parameter to the define() method:

  • AMD adds dependencies to dependencies and obtains dependencies in the factory callback

  • CMD is not loaded in dependencies, but in factory, using require to load a dependency module

Hence the phrase we often see:

The biggest difference between AMD and CMD is that the execution time of the dependent module is different. Note that it is not the loading time or the way is different. Both are asynchronous loading modules.

(Ok, I read it twice carefully, but I still don’t understand it. It’s ok. I will talk about it in detail later.)

Better known as SeaJS, take a look at its recommended format for writing CMD modules:

// All modules are defined with define
define(function(require, exports, module{  
  
  // introduce dependencies via require
  var$=require('jquery');  
  var Spinning = require('./spinning');  
  
  // Provides interfaces through exports
  exports.doSomething = ...  
  
  // The entire interface is available through module.exports
  module.exports = ...  
  
});  
Copy the code

This is a small example from the official website, and I looked it up in the SeaJS documentation and it’s not too much of a problem, so I won’t give you an example.

The difference between AMD and CMD

The biggest difference between AMD and CMD is that the execution time of the dependent module is different. Note that it is not the loading time or the way is different. Both are asynchronous loading modules.

Once again, let’s look at a small example to understand this.

The m1 module also needs to be loaded in the Math module.

In AMD we would write:

math.js

define(['m1'].function (m1{  
  console.log('I'm Math, I'm loaded... ')  
  var add = function (a, b{  
    return a + b;  
  }  
  var print = function ({  
    console.log(m1.name)  
  }  
  return {  
    add: add,  
    print: print  
  }  
})  
Copy the code

But for CMD, we would write:

math.js

define(function (require, exports, module{  
  console.log('I'm Math, I'm loaded... ')  
  var m1 = require('m1');  
  var add = function (a, b{  
    return a + b;  
  }  
  var print = function ({  
    console.log(m1.name)  
  }  
  module.exports = {  
    add: add,  
    print: print  
  }  
})  
Copy the code

If there is a statement in m1.js that prints “I am M1, I am loaded…” when THE M1 module is loaded .

Differences in execution results:

  • AMD will load M1 first, “I am M1” will execute first

  • CMD, I’m “I’m math” will execute first, because in this case console.log(‘ I’m math, I’m loaded… ‘) is placed before require(‘m1’).

Now you can see the difference.

< span style = “box-sizing: border-box; color: RGB (74, 74, 74); line-height: 22px; font-size: 14px! Important; word-break: inherit! Important;”

CMD is near-dependent, meaning that the module’s callback function is not loaded until the statement is loaded.

OK👌, a summary:

The most obvious difference between the two is how dependencies are treated in module definition

1, AMD advocates the dependency front, in the definition of the module should declare its dependent module ****2, CMD advocates the nearby dependency, only when the use of a module to require

ES6 Modules specification

After the ES6 standard came out, ES6 Modules specification has become the mainstream of the front end. More and more people are using import to introduce Modules and export to export interfaces.

Here, I’ll also introduce the ES6 Modules specification from these aspects:

Export and import commands can appear anywhere in the module, as long as they are at the top of the module. If you are in block-level scope, an error will be reported because you cannot do static optimization when you are in conditional code blocks, contrary to the design of the ES6 module.

1. Export Export module

There are two modes for exporting modules:

  • Named export (name export)

  • Default export (custom export)

Name export

Here are some correct and wrong ways to write it:

// The following two are errors
/ / 1.
export 1;  
/ / 2.
const a = 1;  
export a;  
  
// The following is correct
/ / 3.
const a = 1;  
export { a };  
  
// 4. A one-to-one relationship is established between interface names and module variables
export const a = 1, b = 2;  
  
// 5. A one-to-one relationship is established between the interface name and the module's internal variables
export const a = 1;  
export const b = 2;  
  
// Or call it as
const a = 1;  
export { a as outA };  
  
const a = 1;  
const b = 2;  
export { a as outA, b as outB };  
Copy the code

The confusing thing is that the two and the four, they look very similar, but the two doesn’t work. 2 directly exporting a variable with a value of 1 is the same as case 1, which doesn’t make much sense because you won’t be able to deconstruct it when you use it later.

However, in 4, the one-to-one correspondence between the interface name and the internal variables of the module is established, so it can.

The default is derived

The default export is followed by a default:

/ / 1.
const a = 1;  
export default a;  
  
/ / 2.
const a = 1;  
export default { a };  
  
/ / 3.
export default function({}; // You can export a function
export default class(a){}; // You can also create a class
Copy the code

In fact, the default export can be interpreted as another form of named export, that is, the property name of a has been rewritten as default:

const a = 1;  
export defalut a;  
/ / equivalent to the
export { a as default }  
Copy the code

So, we can use const a = 1; export default a; This way a value is derived.

2. Import Import modules

Corresponding to the export module export function, there are two import modes: named import (name import) and default import (definition import).

Let’s see how it’s written:

// An export of a module, moudule
export const a = 1;  
  
// Module import
// 1. A must correspond to the interface name of the loaded module
import { a } from './module'  
  
// 2. Use the as rename
import { a as myA } from './module'  
  
// 3. If you only want to run the loaded module, you can write this, but even if you load it twice, it will only run once
import './module'  
  
// 4. Whole load
import * as module from './module'  
  
// 5. Default and named interfaces
import module, { a } from './module'  
Copy the code

The fourth method takes everything exported from module and assigns it to the module variable so that we can refer to a as module.a.

3. export … from…

Actually, there’s another way to write it, which is to combine export with from.

For example, I have three modules A, B, and C.

Module C now wants to introduce module A, but instead of referring directly to a, it refers to b, so you might expect B to write something like this:

import { someVariable } from './a';  
  
export { someVariable };  
Copy the code

Import someVariable and export.

This is just one variable, so we have to import and export, and if we have a lot of variables that need to be exported, that’s a lot of code.

So this can be done in the following way:

export { someVariable } from './a';

However, there is a caveat to this approach:

  • This approach does not add data to the scope of the aggregation module, meaning that you cannot add data to the scope of the aggregation module (i.eb) used in thesomeVariable.

4. Features of the ES6 Modules specification

To summarize its characteristics:

  • Output using export

  • Input using import

  • You can use export… from… This is written to achieve a “transit” effect

  • The input module variable is not reassigned; it is just a readable reference, but the property can be overwritten

  • Export and import commands can appear anywhere in the module, as long as they are at the top of the module. If you are in block-level scope, an error will be reported because you cannot do static optimization when you are in conditional code blocks, contrary to the design of the ES6 module.

  • The import command is promoted to the top of the module and executed first.

5. ES6 module conversion under Bable

Also, if you have used some ES6 Babel, you will notice that when you use export/import, Babel also converts it to exports/require.

For example, my output:

m1.js:

export const count = 0;
Copy the code

My input:

index.js:

import {count} from './m1.js'  
console.log(count)  
Copy the code

When compiled using Babel, each is converted to:

m1.js:

"use strict";  
  
Object.defineProperty(exports, "__esModule", {  
  valuetrue  
});  
exports.count = void 0;  
const count = 0;  
exports.count = count;  
Copy the code

index.js:

"use strict";  
  
var _m = require("./m1.js");  
  
console.log(_m.count);  
Copy the code

Exports and import are exports and exports.

That means you can use it like this:

// Output module m1.js
exports.count = 0;  
  
  
// index.js
import {count} from './m1.js'  
console.log(count)  
Copy the code

Differences between CommonJS and ES6 Modules specifications

😂, I believe that many people are more concerned about its two areas of other issues, because the basic above try to ask is this. Well, here’s a more detailed summary.

  • CommonJS Modules are run time loaded, ES6 Modules are compile-time output interfaces

  • The CommonJS output is a shallow copy of the value; ES6 Modules output references to values, and changes within the output module can affect the reference changes

  • The module path imported by CommonJs can be an expression because it uses the require() method; ES6 Modules can only be strings

  • CommonJSthis points to the current module, and ES6 Modulesthis points to undefined

  • ES6 Modules doesn’t have these top-level variables: arguments, require, module, exports, __filename, __dirname

The first difference is because CommonJS loads an object (that is, the module.exports property) that is generated only after the script runs. An ES6 module is not an object, and its external interface is a static definition that is generated during the code static parsing phase.

(Should also have some differences I did not expect, welcome to add 👏😊)

Refer to the article

Knowledge is priceless, support original.

Parameter article:

  • The concepts require, import, and export may still be confusing you.

  • Front-end modularity, the Difference between AMD and CMD

  • Use define and require in Node.js

  • CommonJS and ES6 Modules Specifications you Need to know

  • AMD, CMD, CommonJS, ES6 Module

  • “Ruan Yifeng -Module loading Implementation”

This work is reproduced (read the original text)