JavaScript modular parsing

Comprehensive analysis of JavaScript modularity

Definition: modularization refers to the process of dividing the system into several modules from top to bottom when solving a complex problem. It has a variety of attributes and reflects its internal characteristics. Defining modularity is a way to deal with the decomposition of complex systems into better manageable modules. Function modularity is used to segment, organize and package software. Each module completes a specific sub function, and all modules are assembled in some way to form a whole to complete the functions required by the whole system.

1, What is modularity of JavaScript?

With the development of the Internet, web pages are more and more like desktop programs, which need a team division of labor and cooperation, schedule management, unit testing, etc. developers have to use the method of software engineering to manage the business logic of web pages.
Javascript modular programming has become an urgent need. Ideally, developers only need to implement the core business logic, and others can load modules already written by others.
However, Javascript is not a modular programming language. It does not support "class", let alone "module" (the sixth edition of ECMAScript standard under development will officially support "class" and "module", but it will take a long time to put into practice.)
The Javascript community has made a lot of efforts to achieve the effect of "module" in the existing running environment. This paper summarizes the current best practices of "Javascript modular programming" and explains how to put it into practice. Although this is not a preliminary tutorial, you can understand it as long as you have a little understanding of the basic syntax of Javascript.

When JavaScript was modularized at the beginning, we simply split the JavaScript code in the form of files, and then introduce it according to the needs of HTML files.

Here we create several Javascript files:

// module_1.js
var a = [1, 2, 3, 4, 5];

// module_2.js
var b = a.concat([6, 7, 8, 9, 10]);

//module_3.js
var c = b.join('-')

// index.js
console.log(a);
console.log(b);
console.log(c);

Then we create a new index HTML file and import the above Javascript files:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="js/module_1.js"></script>
<script src="js/module_2.js"></script>
<script src="js/module_3.js"></script>
<script src="js/index.js"></script>
</body>
</html>

Finally, the operation results are obtained:

This is the original writing method of our javascript code, which divides the function code in the form of splitting files to make the code better maintained. However, this writing method will encounter many problems, such as changing the introduction order of files:

<script src="js/index.js"></script>
<script src="js/module_1.js"></script>
<script src="js/module_2.js"></script>
<script src="js/module_3.js"></script>


The reason for the error is that the JS engine is blocked when loading JS. When downloading index JS will first parse index JS, wait until it is completed before going back to the next step, so index An error is thrown when there is no a variable in JS.
So at the beginning, we must determine the loading order of files according to the logic of the code.
Question 2:
js files introduced into the same html file will share a scope (global scope). The variable we declare in any file will be a global variable. When two files have the same variable name, the variable will be overwritten, which is what we often call "global pollution".

From the above, we can conclude that modularization solves two major problems:

  1. Loading order
  2. Global pollution

2, Execute function now

As we said above, modularization solves two problems. In order to solve the problem of global pollution, the immediate execution function came into being.

;(function () {
	// Scope 	//  Execution context
})();

The immediate execution function is different from the ordinary function. The ordinary function is not an expression. It needs to be called before it can be executed, and the immediate execution function can be executed by itself. We know that functions have their own scope and execution context. We can use this to create an independent scope of a module, so as to avoid global pollution.

Let's modify the above code:

// module_1.js
var module_1 = (function () {
  var a = [1, 2, 3, 4, 5]
  return {
    a: a
  }
})()

// module_2.js
var module_2 = (function (module_1) {
  var b = module_1.a.concat([6, 7, 8, 9, 10])

  return {
    b: b
  }
})(module_1)

//module_3.js
var module_3 = (function (module_2) {
  var c = module_2.b.join('-')
  return {
    c: c
  }
})(module_2)

// index.js
;(function (module_1, module_2, module_3) {
  console.log(module_1.a);
  console.log(module_2.b);
  console.log(module_3.c);
})(module_1, module_2, module_3);


There is no change in the running results, and we pass the module in the form of parameters, which also solves the problem of module dependency.

2, Changes brought by NodeJS to Modularity

The immediate execution function above solves the problem of global pollution, but the problem of file import order has not been solved. The emergence of NodeJS not only solves the problem of file import, but also solves the problem that js files can only be imported through HTML.

require('...') 	// Import module
module.exports	//Export module

Because you want to use the modularization of NodeJS, you need to install node (installed by yourself), and then make the following modifications to the project:

Execute npm init -y in the root directory (generate package.json file)
Install webpack and some plug-ins in package Add the run and package commands to the scripts of the JSON file:

Create a new webpack from the root directory config. JS file:

Because it is only for demonstration, only some simple configurations are made here

// webpack.config.js 	 (commonJS specification)

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  mode: 'development',
  output: {
    path: path.join(__dirname, 'dist'),
    filename: 'index.js'
  },
  entry: path.join(__dirname, 'src', 'main.js'),
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'index.html'),
      filename: 'index.html'
    })
  ],
  devServer: {
    port: '8889',
    static: path.join(__dirname, 'dist')
  }
}

Code modification:

// module_1.js
var a = (function () {
  return [1, 2, 3, 4, 5]
})();

module.exports = {
  a
}

// module_2.js
var module_1 = require('./module_1');
var b = (function () {
  return module_1.a.concat([6, 7, 8, 9, 10])
})();

module.exports = {
  b
}

// module_3.js
var module_2 = require('./module_2');
var c = (function () {
  return  module_2.b.join('-')
})();

module.exports = {
  c
}

// main.js(webpack packaged entry file)
var module_1 = require('./js/module_1');
var module_2 = require('./js/module_2');
var module_3 = require('./js/module_3');
console.log(module_1.a);
console.log(module_2.b);
console.log(module_3.c);

Execute npm run dev:
Get running results

1.CommonJS specification

CommonJS is a modular specification provided by NodeJS

  1. CommonJS will create a module instance for the referenced js file as long as it is referenced once.
  2. Each request will cache this instance, and it will be directly obtained from the cache when it is loaded again.
  3. Must rely on NodeJS and cannot run on the client.
  4. CommonJS loads modules synchronously.

See: CommonJS specification - JavaScript standard reference tutorial (alpha)

2.AMD specification

AMD is the abbreviation of "Asynchronous Module Definition", which means "Asynchronous Module Definition". It loads modules asynchronously, and the loading of modules does not affect the operation of subsequent statements. All statements that depend on this module are defined in a callback function. The callback function will not run until loading is completed.

  1. The module is loaded asynchronously without blocking.
  2. A modular specification that can run on the client based on CommonJS transformation.
  3. Dependent on require JS library.
  4. Before dependency, the dependent module executes in advance.

Syntax:

Define module: define(moduleName, [module], factor) // moduleName: module name, [module]: module to depend on, factor: callback function
Import module: require([module], factor) // module: dependent module, callback: execute function

Next, we use AMD specification to transform the above code:

Since AMD specification requires JS, so we are in index Introduce require. HTML file js
CDN address of amd: https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.min.js

Modification code:

// module_1.js
define('module_1', function () {
  var a = [1, 2, 3, 4, 5]
  return {
    a: a
  }
})

// module_2.js
define('module_2', ['module_1'], function (module_1) {
  var b = module_1.a.concat([6, 7, 8, 9, 10])
  return {
    b: b
  }
})

//module_3.js
define('module_3', ['module_2'], function (module_2) {
  var c = module_2.b.join('-')
  return {
    c: c
  }
})

// index.js
require.config({ // The paths of all dependent files need to be configured in the final imported entry file, otherwise an error will be reported because the dependent file cannot be found
  paths: {
    module_1: 'module_1',
    module_2: 'module_2',
    module_3: 'module_3'
  }
})

require(
  ['module_1', 'module_2', 'module_3'],
  function (module_1, module_2, module_3) {
    console.log(module_1.a);
    console.log(module_2.b);
    console.log(module_3.c);
  }
)

3.CMD specification

CMD is the Common Module Definition. The CMD specification has been developed in China, just like AMD has a requireJS and CMD has a browser implementation of seajs. The problems to be solved by seajs are the same as requireJS, but there are differences in the module definition method and the module loading (operation and analysis) time

  1. Load modules asynchronously.
  2. It depends on the nearest location and is loaded only when it is used.

Syntax:

Define module: define(function(require, exports, module){}) // require: used to obtain interfaces provided by other modules, exports: provide module interfaces externally, module: an object that stores some properties and methods associated with the current module
Import module: seajs use([module], factor)

CDN of seajs: https://cdn.bootcdn.net/ajax/libs/seajs/3.0.3/sea.js

Code modification:

// module_1.js
define(function (require, exports, module) {
  var a = [1, 2, 3, 4, 5]
  return {
    a: a
  }
});

// module_2.js
define(function (require, exports, module) {
  var module_1 = require('./module_1'),
      b = module_1.a.concat([6, 7, 8, 9, 10])
  return {
    b: b
  }
});

//module_3.js
define(function (require, exports, module) {
  var module_2 = require('./module_2'),
      c = module_2.b.join('-')
  return {
    c: c
  }
});

// index.js
seajs.use(['./module_1.js', './module_2.js', './module_3.js'], function (module_1, module_2, module_3) {
  console.log(module_1.a);
  console.log(module_2.b);
  console.log(module_3.c);
})

4.6 modularization

In previous javascript, there was no concept of modularity. If you want to carry out modular operation, you need to introduce a third-party class library. With the development of technology and the separation of front-end and back-end, the front-end business becomes more and more complex. It was not until ES6 brought modularity that javascript supported module for the first time. The modularization of ES6 is divided into two modules: export and import.

Syntax:

import moduleName from '...' / / import
import moduleName as Name from '...' / / import rename
import {moduleName,...} from '...' / / import on demand
import {moduleName as Name,...} from '...' / / rename as needed
Export / / export
export default / / export by default
...

summary

Both AMD (requireJS) and CMD (seaJS) are implemented based on the CommonJS specification, but there are two significant differences between the modular specification of ES6 and the CommonJS specification:

  1. CommonJS outputs a copy of a value, while ES6 outputs a reference to a value.
  2. CommonJS modules are loaded at runtime, while ES6 modules are loaded at compile time.

Keywords: Javascript Front-end

Added by LDusan on Mon, 03 Jan 2022 22:57:30 +0200