Modularized development can improve code reuse rate and facilitate code management. Usually a file is a module with its own scope, exposing only specific variables and functions. Popular JS modular specifications include CommonJS, AMD, CMD and ES6 module systems. See Teacher Ruan Yifeng’s article module-loader.

First, the CommonJS

Node.js is a major practitioner of the commonJS specification and has four important environment variables to support modular implementations: Module, exports, require, global. Module. exports defines the interface for the current module’s exports (not recommended), and requires loads the module.

Math.js var basicNum = 0;function add(a, b) {
  returna + b; } module.exports = {// add: add, basicNum: basicNum} // module.exports = {// add: add, basicNum: basicNum} // add: add, basicNum: basicNum}'./math'); math.add(2, 5); Var HTTP = require('http'); http.createService(...) .listen(3000); Copy the codeCopy the code

CommonJS loads modules synchronously. On the server side, the module files are stored on local disk and are very fast to read, so this should not be a problem. However, on the browser side, it is more reasonable to use asynchronous loading for network reasons.

AMD and require.js

The AMD specification uses asynchronous loading of modules, which does not affect 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. Here is an introduction to implement the modularization of the AMD specification with require.js: specify the reference path with require.config(), define the module with define(), and load the module with require().

First we need to import the require.js file and an entry file main.js. Configure require.config() in main.js and specify the base module to use in the project.

/** / <script SRC ="js/require.js" data-main="js/main"></script> /** main.js entry file/main module **/ /"js/lib",
  paths: {
    "jquery": "jquery.min"// The actual path is js/lib/jquery.min.js"underscore": "underscore.min",}}); // require(["jquery"."underscore"].function($,_){ // some code here }); Copy the codeCopy the code

When referencing modules, we place the module name in [] as the first argument to reqiure(); If we define modules that themselves depend on other modules, we need to place them in [] as the first argument to define().

// define math.js module define(function () {
    var basicNum = 0;
    var add = function (x, y) {
        return x + y;
    };
    return{ add: add, basicNum :basicNum }; }); // Define a module define(['underscore'].function(_){
  var classify = function(list){
    _.countBy(list,function(num){
      return num > 30 ? 'old' : 'young'; })};return{ classify :classify }; }) // put the module in [] require(['jquery'.'math'].function($, math){var sum = math.add(10,20); $("#sum").html(sum); }); Copy the codeCopy the code

CMD and sea-.js

Require.js loads and executes the code in the module when it declares a dependent module:

define(["a"."b"."c"."d"."e"."f"].function(a, b, c, d, e, f) {// All modules that need to be used are declared and initialized firstif (false) {// even if a module b is not used, but b is still ahead of time b.foo()}}); Copy the codeCopy the code

CMD is another JS modularization solution, which is similar to AMD, except that AMD advocates relying on front-loading and up-front execution, while CMD advocates relying on nearby and delayed execution. This specification was actually created during the promotion of Sea-js.

/** AMD define **/ define(["a"."b"."c"."d"."e"."f"].function(a, b, c, d, e, f) {// initialize all modules that need to be used first.if (false) {// Even if a module b is not used, b is still implemented ahead of time b.dosomething ()}}); /** CMD **/ define(function(require, exports, module) {
    var a = require('./a'); // declare a.dosomething () if needed;if (false) {
        var b = require('./b'); b.doSomething(); }}); /** sea-.js ** math.js define(function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        returna+b; } exports.add = add; }); Seajs.use ([)'math.js'].function(math){ var sum = math.add(1+2); }); Copy the codeCopy the code

Fourth, the ES6 Module

ES6, on the level of language standards, implements module functions, and implements them quite simply, aiming to become a common module solution for browsers and servers. Its module functions are mainly composed of two commands: export and import. The export command is used to specify the external interface of a module, and the import command is used to input functions provided by other modules.

Math.js **/ var basicNum = 0; var add =function (a, b) {
    return a + b;
};
export{ basicNum, add }; Import {basicNum, add} from'./math';
function test(ele) { ele.textContent = add(99 + basicNum); } Duplicate codeCopy the code

As shown in the example above, when using the import command, the user needs to know the name of the variable or function to be loaded. In fact, ES6 also provides the export default command, which specifies the default output of the module. The corresponding import statement does not need curly braces. This is also closer to ADM’s citation style.

/ * *exportDefault **/ / define the outputexportdefault { basicNum, add }; // Import math from'./math';
function test(ele) { ele.textContent = math.add(99 + math.basicNum); } Duplicate codeCopy the code

ES6 modules are not objects, and the import command is statically analyzed by the JavaScript engine. The module code is introduced at compile time, rather than loaded at run time, so conditional loading cannot be implemented. Because of this, static analysis is possible.

5. Differences between ES6 module and CommonJS module

1. The CommonJS module outputs a copy of a value, while the ES6 module outputs a reference to a value.

  • The CommonJS module outputs a copy of the value, meaning that once a value is output, changes within the module do not affect that value.
  • ES6 modules operate differently from CommonJS. The JS engine encountered a module load command while statically analyzing the scriptimport, a read-only reference is generated. When the script is actually executed, it will be evaluated in the loaded module based on the read-only reference. In other words, ES6importIt’s kind of like a symbolic link on Unix, where the original value changes,importThe loaded value will also change. Therefore, ES6 modules are referenced dynamically and do not cache values. Variables in modules are bound to the module in which they are located.

2. CommonJS module is run time loading, ES6 module is compile time output interface.

  • Runtime loading: CommonJS modules are objects; That is, the entire module is loaded on input, an object is generated, and methods are read from that object. This loading is called “runtime loading.”

  • Compile-time loading: ES6 modules are not objects, but are output code explicitly specified through the export command and static commands when importing. That is, when you import, you can specify that an output value is loaded instead of the entire module, which is called “compile-time loading.”

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.