preface

Before we can understand JS modularity, we need to know the history of JS

First of all, before ES6, because there was no engine dedicated to JS, the rendering engine was still responsible for JS, so the large size of JS files would affect the loading speed of web pages

Hence the concept of modularity.

JS file modularization history

1. Import the js file

  • The original JS script is written directly into the script tag in HTML
<script type="type/javascript"> <! -- Script file --> </script>Copy the code
  • Separate the JS script

Introduced by the script tag

<script type="type/javascript" src="./index.js"></script>
Copy the code

But as JS has to do more and more, the concept of modularity has emerged to make it easier to distinguish between script files that precede each page

2. Modularity origins

  • The js file is responsible for individual pages

We want each JS file to be responsible for only one page, so we divide the different JS files into pages

  • Common JS file

When two pages do the same thing, such as a function for loading ICONS, we find that the code is duplicated, which is not efficient, so we extract the common function and put it in a common JS file. Then reintroduce it with the script tag on the desired page

  • Program division

When the page is complex, there are many things in the common JS file that the page does not need, which adds to the burden

So, thinking that you can’t partition JS files by pages, start to partition JS scripts by programs

For example, a website, most pages need this function of the wheel cast map, so the control wheel cast map JS written in a separate JS file

3. Modular development

3.1 Discovering Faults

In the previous development, slowly formed the prototype of modular, but there are many problems

  • Load order
<script type="type/javascript" src="./login.js"></script>
<script type="type/javascript" src="./content.js"></script>
Copy the code

When importing different JS files using the script tag, the js engine will block subsequent JS file loading when it encounters the JS file.

Therefore, if there is a dependency between the two when the HTML is placed in the imported JS file, for example, some functions in content.js need to use variables in the login.js file, it can only be placed after login.js

  • Global pollution

As you can see from the above example, variables in the imported JS file are exposed globally without adding any protection.

Assume the var temp=1 in login. We also have the same variable temp = 2 in content

In this case, there will be variables with the same name, and then there will be a variable temp=2 overwrites the previous temp, which may affect the implementation of some functions

3.2 Troubleshooting

3.2.1 Execute the function immediately
  • The semicolon issues
; (function(){ })()Copy the code

Most of you probably don’t think about why you need a function; .

In the first place. Is at the beginning of JS design is a sign of the end of a statement, that it is as a standard we should comply with, but in our daily code process to write or not to write, will not affect the implementation of the code.

So why do I need to add;

This is because browsers don’t know where to end statements when multiple self-executing functions are added together, like the following

  (function(){
      console.log(1)
  })()
  (function(){
     console.log(1)
  })()
Copy the code

When we add; You can tell after that

Get back to business

How does executing the function immediately solve the problem?

  1. Local scope

A self-executing function has its own execution-time context, and external variables cannot access variables in the inner scope, so it has the prototype of a module’s independent scope

  1. External access

For variables that need to be accessed externally, they need to be thrown in the following manner

You might ask, why put it in an object instead of just returning

In fact, it is easy to expand the question, suppose we need to return a number of variables, do we return one by one

  1. Module into

And soon you’ll see the new problem, that this way of doing it, is a closure.

In this case, we know that when we return a variable, the variable is not in global scope, but simply returns the scope of the self-executing function to global scope

That is, the function is destroyed, but its scope is not.

Since variables are not in the global scope, if two JS files have dependencies, how does the other JS file get the related variables?

Suppose the file structure is now as follows

  • IndexA. Js file
;(function () {
        var a = [1,2,3];
        return {
          a:a
        }
      })()
Copy the code
  • IndexB. Js file
; (function () { var b = a.reverse(); return { b:b } })()Copy the code

This is where indexB requires the A variable in indexA and hence the concept of module injection

Create a variable to receive the returned data

Modules can be independent and dependent on each other, enabling on-demand invocation – injecting whatever modules are needed, eliminating the problem of global contamination and dependency.

But it does not solve the loading order problem

4. NodeJS brings new modularity

NodeJS makes modules truly independent and interdependent. No longer rely on dependencies between HTML page implementation modules

Module. Exports uses require imports, module. Exports

4.1 CommonJS

CommonJS is a modular specification derived from NodeJS

Its features are:

  1. Use require for import
var moduleA = require('./indexA')
Copy the code

Note: require is not a global variable

It’s actually a self-executing function

  1. Export using module.exports
module.exports={
moduleA
}
Copy the code
  1. synchronous

All files are loaded synchronously

  1. Caching mechanisms

For the server, require once will automatically cache the module, compare the similarities and differences each time, and if there is no change, require will not be executed

  1. The Node environment

It can only run on Node without webpack parsing

4.2 AMD

  • **Asynchronous Module Definition **

Asynchronous module definition

As you can see above, it is asynchronous

Asynchrony emphasizes that when loading modules and other modules on which modules depend, asynchrony loading is adopted to avoid module loading blocking the webpage rendering progress

  • API

It is also intended as a specification, with only one syntax API—-define function

define([module-name?] , [array-of-dependencies?] , [module-factory-or-object]);

Module-name: indicates the module id

Array-of-dependencies: Specifies the module on which it depends

Module-factory-or-object: implementation of a module

The define function, which is also asynchronous, is loaded as follows

Call the module that the second argument depends on, and when it’s all loaded, the third argument, if it’s a callback, will handle the code

2 RequireJS

The AMD starter client is also not supported, but it relies on RequireJS.

RequireJS is AMD compliant

  • rewrite

RequireJS

Define () defines the module

Require uses modules

The above indexA and indexb.js files can be written as follows

In addition, RequireJS can configure paths

We can do this when we need to print variables A and B in main.js

4.2.2 Front Dependencies

When this module is loaded, all dependent modules need to be loaded in advance before the relevant code can be executed

The callback function, such as the a and B variables printed above, is dependent on the previous moduleA and moduleB modules. The dependent modules are loaded at the same time, regardless of the loading order. The callback function is executed only when the required module files are loaded

This is AMD’s greatest strength

4.3 CMD

Common Module Definition Common Module Definition

4.3.1 SeaJS

Define (function(require, exports, module) {// module code}); To define a module

Seajs. use([module path], function(module…) ) Using modules

  • rewrite

Rewrite the AMD example above

Mainjs used in


seajs.use(['indexA.js','indexB.js'],function (moduleA,moduleB) {
  console.log(moduleA.a);
  console.log(moduleB.b)
})
Copy the code

Exports/module/module/require

You need to configure module URL dependencies to be loaded before executing

4.3.2 Nearby Dependency
  • To rely on

If you need to reference moduleA, require references to it —- load on demand

5. ES6 modularity

ES6 formally defines modules as a specification

Import module from ‘module path ‘; —— Importing a module

Export Module —— Export module

  • rewrite

6.ES6 differs from CommonJS

  1. Import, export mode
  • CommonJS

Require import —–module.exports

  • ES6

Import Import —–export Export

  1. Loading time
  • CommonJS is run time loaded

  • ES6 is a compile-time output interface

  1. Synchronous asynchronous
  • CommonJS

Require is synchronous loading

  • ES6

Import is loaded asynchronously

4. Essential differences

Common is the output is a copy of the value

That is, changes within the module do not affect this value

It is obvious that the execution of the counter function inside the module does not affect the output variable

The ES module outputs references to values

The module clearly outputs a reference to A