Modularized development method 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 modularity specifications include CommonJS, AMD, CMD, and ES6 module systems. See Ruan Yifeng’s article modole-Loader.

First, the CommonJS

Node.js is the main practitioner of the commonJS specification, and it has four important environment variables that support modular implementations: Module, exports, require, and global. For actual use, use module.exports to define the interface of the current module and use require to load the module.

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

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

2. AMD and require.js

The AMD specification loads modules asynchronously, so that the loading of the module does not affect the execution of the statements following it. All statements that depend on this module are defined in a callback function that will not run until the load is complete. Here is how to implement AMD specification modularity with require.js: specify reference paths with require.config(), define modules with define(), and load modules with require().

First we need to introduce the require.js file and an entry file main.js. Configure require.config() in main.js and specify the base modules to be used in the project.

/** introduce require.js and main.js **/ <script SRC ="js/require.js" data-main="js/main"></script> /** main.js entry file/main module **/ // / first use config() to specify the module path and reference name require.config({baseUrl:"js/lib",
  paths: {
    "jquery": "jquery.min"// The actual path is js/lib/jquery.min.js"underscore": "underscore.min",}}); // Perform the basic operation require(["jquery"."underscore"].function($,_){
  // some code here
});
Copy the code

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

// Define the 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]'underscore'].function(_){
  var classify = function(list){
    _.countBy(list,function(num){
      return num > 30 ? 'old' : 'young'; })};return{ classify :classify }; }) // reference the module and place it inside [] require([]'jquery'.'math'].function($, math){var sum = math.add(10,20); $("#sum").html(sum);
});
Copy the code

CMD and sea-.js

When require.js declares a dependent module, it loads and executes the code in the module first:

define(["a"."b"."c"."d"."e"."f"].function(a, b, c, d, e, f)if (false) {// b.foo()}});Copy the code

CMD is another JS modularization solution, which is very similar to AMD, except that WHEREAS AMD advocates dependency forward and early execution, CMD advocates dependency near and late execution. This specification was actually produced during the promotion of sea-.js.

/** AMD **/ define(["a"."b"."c"."d"."e"."f"].function(a, b, c, d, e, f) {// equals to declare and initialize all modules to be used in the first place a.dosomething ();if (false) {// b. dosomething ()}}); /** define()function(require, exports, module) {
    var a = require('./a'); // declare a.dosomething () when needed;if (false) {
        var b = require('./b'); b.doSomething(); }}); /** sea-.js **/function(require, exports, module) {
    var $ = require('jquery.js');
    var add = function(a,b){
        returna+b; } exports.add = add; }); Seajs.use ([seajs.use])'math.js'].function(math){
    var sum = math.add(1+2);
});
Copy the code

Fourth, the ES6 Module

ES6 implements modular functionality at the language standard level and is fairly simple to implement, aiming to be a common browser and server modular solution. The module function consists of two commands: export and import. The export command is used to specify the external interfaces of a module. The import command is used to enter the functions provided by other modules.

/** define module math.js **/ var basicNum = 0; var add =function (a, b) {
    return a + b;
};
export{ basicNum, add }; /** reference module **/ import {basicNum, add} from'./math';
function test(ele) {
    ele.textContent = add(99 + basicNum);
}
Copy 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. ES6 also provides the export default command, which specifies the default output for the module. The corresponding import statement does not need braces. This is also more similar to the ADM reference writing.

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

Modules in ES6 are not objects, and the import command is statically analyzed by the JavaScript engine, and the module code is introduced at compile time rather than loaded at run time, so conditional loading is not possible. This is what makes static analysis possible.

5. Differences between ES6 module and CommonJS module

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

  • The CommonJS module outputs a copy of the value, which means that once a value is printed, changes within the module cannot affect it.
  • The ES6 module operates differently from CommonJS. The JS engine encountered the module load command while statically analyzing the scriptimport, a read-only reference is generated. When the script actually executes, the value is then applied to the loaded module based on the read-only reference. In other words, ES6importKind of like a “symbolic link” on Unix systems, where the original value changes,importThe loaded values will also change. Therefore, THE ES6 module is a dynamic reference and does not cache values, and variables within the module are bound to the module in which they reside.

2. The CommonJS module is a runtime load, and the ES6 module is a compile-time output interface.

  • Runtime loading: CommonJS modules are objects; That is, the whole module is loaded, an object is generated, and then the method is read from the object. This kind of loading is called “run time loading”.

  • Load at compile time: AN ES6 module is not an object, but rather code that is explicitly specified for output via the export command, and a static command when importing. That is, you can specify to load an output value at import, rather than load the entire module. This type of load is called “compile time load.”

CommonJS loads an object (the module.exports property) that will only be generated after the script has run. While an ES6 module is not an object, its external interface is just a static definition, which is generated during the static code parsing phase.

(This article is only for personal memo record purposes, some quotes from the Internet with personal understanding. Welcome to reprint, please indicate the source. Feel free to tip if it helps you.