How to correctly understand the modularization of javascript

  • 2021-07-26 06:08:37
  • OfStack

Modularization in the project of 10 points of importance, a complex project must have many similar functional modules, if each need to rewrite the module must be time-consuming and labor-intensive. However, the premise of quoting others to write modules is to have the "open posture" of Unified 1. If everyone has their own writing style, it will definitely be confused. Here are several modular specifications of JS.

1: Modular Process 1: script Tag

This is the most primitive loading method of JavaScript files. If every file is regarded as a module, their interfaces are usually exposed to the global scope, that is, defined in window objects. The interface calls of different modules are all in a scope, and some complex frameworks will use the concept of namespace to organize the interfaces of these modules.

Disadvantages:

1. Global scope of pollution

2. Developers must subjectively resolve the dependencies between modules and code bases

3. Files can only be loaded according to the writing order of script tags

4. It is difficult to manage all kinds of resources in large-scale projects, and the long-term accumulated problems lead to the confusion of the code base

2: Modular Process 2: CommonJS Specification

The core idea of this specification is to allow modules to load other modules that they depend on synchronously through the require method, and then export interfaces that need to be exposed through exports or module. exports.


require("module");
require("../file.js");
exports.doStuff = function(){};
module.exports = someValue;

Advantages:

1. Simple and easy to use

2. Server-side modules are easy to reuse

Disadvantages:

1. Synchronous module loading mode is not suitable for browser environment. Synchronization means blocking loading, and browser resources are loaded asynchronously

2. Multiple modules cannot be loaded in parallel without blocking

The difference between module. exports and exports

1. exports is a reference to module. exports

2. The initial value of module. exports is 1 empty object {}, so the initial value of exports is also {}

3. require () returns module. exports instead of exports

Example of exports:


// app.js
var circle = require('./circle');
console.log(circle.area(4));
// circle.js
exports.area = function(r){
 return r * r * Math.PI;
}

module. exports example:


// app.js
var area = require('./area');
console.log(area(4));
// area.js
module.exports = function(r){
 return r * r * Math.PI;
}

Wrong situation:


// app.js
var area = require('./area');
console.log(area(4));
// area.js
exports = function(r){
 return r * r * Math.PI;
}

In fact, it covers exports. That is to say, exports points to a new block of memory (the content is a function to calculate the circle area), that is to say, exports and module. exports no longer point to the same block of memory, that is to say, exports and module. exports have no connection at this time, that is to say, the block of memory pointed by module. exports has not been changed, and it is still an empty object {}, that is to say, area. js exports an empty object, so we call area (4) in app. js

Summary: exports and module. exports can be used when we want the module to export an object (but exports cannot be overwritten as a new object), while module. exports must and can only be overwritten when we want to export a non-object interface.

3: Modular Process 3: AMD Specification

Because the modules on the browser side cannot be loaded synchronously, which will affect the loading execution of subsequent modules, AMD (Asynchronous Module Definition asynchronous module definition) specification was born.

The following two API are defined in the AMD standard

1. require ([module], callback);
2. define (id, [depends], callback);

The require interface is used to load a series of modules, and the define interface is used to define and expose a module.

Example:


define("module", ["dep1", "dep2"], function(d1, d2){
 return someExportedValue;
});
require(["module", "../file"], function(module, file){ /* ... */ });

Advantages:

1. Suitable for loading modules asynchronously in browser environment

2. Multiple modules can be loaded in parallel

Disadvantages:

1. The development cost is increased, the reading and writing of code is difficult, and the semantics of module definition is not smooth

2. It does not conform to the general modular thinking mode and is the realization of a compromise

4: Modular Process 4: CMD Specification

The CMD (Common Module Definition) specification is similar to AMD, keeps it as simple as possible, and maintains great compatibility with Modules specifications of CommonJS and Node. js. In the CMD specification, a module is a file.

Example:


define(function(require, exports, module){
 var $ = require('jquery');
 var Spinning = require('./spinning');
 exports.doSomething = ...
 module.exports = ...
})

Advantages:

1. Depend on the nearest place and delay execution

2. It can be easily run in Node. js

Disadvantages:

1. Depending on SPM packaging, the loading logic of modules is biased

Differences between AMD and CMD

AMD and CMD are very similar, but there are still some subtle differences. Let's take a look at the differences between them:

1. For dependent modules, AMD is executed early and CMD is executed late.

2. AMD advocates dependence front; CMD advocates relying on proximity, and only goes to require when a certain module is used. Look at the code:


// AMD
define(['./a', './b'], function(a, b){ //  Dependence must 1 Write it at the beginning 
  a.doSomething()  
  //  Omitted here  100  Row 
  b.doSomething()  
  ...
});
// CMD
define(function(require, exports, module){
  var a = require('./a')  
  a.doSomething()  
  //  Omitted here  100  Row 
  var b = require('./b')
  //  Dependence can be written nearby 
  b.doSomething()
  // ...
});

3. By default, API of AMD is used for multiple purposes, while API of CMD is strictly distinguished, and duty list 1 is respected.

5: Modularization Process 5: ES6 Modularization

EcmaScript6 standard adds the definition of module system at JavaScript language level. The design idea of ES6 module is as static as possible, so that the dependencies of modules, as well as input and output variables can be determined at compile time. Both CommonJS and AMD modules can only determine these things at runtime.

In ES6, we use the export keyword to export the module and the import keyword to reference the module. It should be noted that this set of standards of ES6 is not directly related to the current standards, and few JS engines can directly support it at present. So what Babel does is actually translate the unsupported import into the currently supported require.

Although there is little difference between using import and require at present (it is essentially the same thing), it is strongly recommended to use import keyword, because once JS engine can resolve import keyword of ES6, the whole implementation will change greatly from the current one. If you start using the import keyword now, there will be very little code change in the future.

Example:


import "jquery";
export functiondoStuff(){}
module "localModule" {}

Advantages:

1. Easy static analysis

2. Future-oriented EcmaScript standard

Disadvantages:

1. The native browser has not yet implemented this standard

2. A brand-new command word, which is supported by the new version of Node. js


Related articles: