All large applications are developed using modularity, which is the breaking down of a complex system into separate modules that can be easily maintained later.

  1. High maintainability: The front-end passes over a long period of time
  2. Name conflict: objects created by JS will become global objects, so there is no namespace way, will cause a lot of problems, the introduction of third-party libraries may also be named overwriting
  3. High reusability

The above are all problems with modularity, so how can we solve these problems and make the front end support modular development

1. Namespace mode

In simple terms, we will simulate the concept of namespaces through JS objects

  • In this way, we think of the simulated namespace as a module. The Module reduces global variables and resolves naming conflicts by means of objects

  • ** However, internal variables can be solved without external ones. The name is also exposed and can be changed at will, which is not what modularity wants

    var namespace = {
        name: 'namespace',
        getName: function() {
            return this.name
        }
    }
    namespace.name
    namespace.getName()
    Copy the code

    六四动乱

2.IIFE

  • In order to avoid global variable pollution, JS provides modularization scheme in the way of closure. We avoid variables leaking into the global scope by self-executing functions

  • Data is private scoped, and only methods operate on private variables

    (function(window) {
      let name = 'private'
      var module = {
        getName: function() {
          return name
        },
        setName: function() {
          return name + 'Set'
        }
      }
      window.module = module
    })(window)
    Copy the code

If the module is mounted under the window above, the module only exposes getName and setName methods. The internal name cannot be changed

  • However, there is a problem with this pattern. If I want to introduce other dependency libraries, I still cannot reference the global dependency libraries. For example, if I want to introduce jQuery, I will inject dependencies into the module

  • This pattern is also called IIFE Pattern Enhancement

  • This enables modularity and makes module dependencies a little clearer

    (function(window, jQuery) {
      let name = 'private'
      var module = {
        getName: function() {
          return name
        },
        setName: function() {
          return name + 'Set'
        }
      }
      window.module = module
    })(window, jQuery)
    Copy the code

3. The CommonJS specification

With the application of JS in the server, there is an urgent need for a standardized modular solution. Node.js is applied to this specification after the proposal of CommonJS specification.

  • Each file is a module and has its own scope
  • Variables, functions, and classes in one file are private and invisible to other files
  • Modules in Node are loaded synchronously at runtime

1. Use: expose object with module, require introduce module

Exports = {a: 1} var moduleA = require('./module.js')Copy the code

2. Module loading mechanism

The required object is a copy of the module.exports exposed object, but it is observed that if two modules introduce a module together, if one module extends the current module, the other modules will be introduced with the same value except for the key defined by the module initialization. Other new keys also interact with each other across modules

3. Use the CommonJS specification on the browser side, which can be parsed with Browserify,gulp, webpack, etc and imported into the page. Browserify is mainly introduced here

/ / definition module A moduleA. Js module. Exports = {A: Moduleb. js var moduleB = require('./ modulea.js ') console.log(moduleB) module.exports = {B: 2}Copy the code

Once defined, install Browserify

npm install --save-dev Browserify
Copy the code

The package command puts the package name in the scripts of package.json

"scripts":{
    "build": "browserify moduleB.js -o build.js"
}

npm run build
Copy the code

Importing the packaged build.js file into the HTML file is used

4.AMD (Asynchronous Module Definition)

This is also a kind of JS modular specification, CommonJS adopts synchronous loading mode, only modules can be loaded after the operation, AMD mainly provides asynchronous loading function, requires RequireJS to achieve modular writing, browsers generally need to load modules from the server, all the use of asynchronous loading will be better

1. Basic grammar

Define a module: Use the define method to define code as a module

// moduleA.js define(function(){ return { ... module } })Copy the code

Reference a module: Load a module using the require method

Function (moduleA){require(['moduleA'], function(moduleA){Copy the code

2. Benefits of using AMD in browsers

  • Modules are clearly defined, no longer need to write self-executing functions, and do not pollute the global environment
  • Clearly show dependencies

5.CMD( Common Module Definition)

CMD specification is specially used for browser side, module loading is asynchronous, the module will be loaded and executed when the module is used. CMD integrates the characteristics of CommonJS and AMD specifications, and the corresponding library is SeaJS, which is the same as requireJS, to solve the problem of asynchronous loading, but is different in the use method and loading time

  • After CMD loads a module dependency, it is not executed. Instead, it is downloaded and the main logic is entered after all dependencies are loaded
  • The corresponding module is executed when the require statement is encountered, so that the execution order of the module is exactly the same as the writing order. Lazy loading of the module can be realized by using require.async()

1. Basic use

ModuleA, modulea. js define(function(require, exports,) Module) {let a = 'aaa' module.exports = a}) // define moduleB, moduleb. js define(function(require, exports, Module){var a = require('./a') var aa = require.async('./a') Function (MA) {}) var b = 'BBB' console.log(a, Module.exports = B}) define(function(require){var B = require('./ moduleb.js ')}) // Sea.js import entry file seajs.use('./main')Copy the code

6.UMD

UMD (Universal Nodule Definition) is a Universal Nodule Definition that is compatible with AMD, CommonJS, and CommonJS. Many JS frameworks and libraries are packaged in this form, and the implementation of UMD is as follows

  • Check whether CommonJs modules (exports exist) are supported. If so, use CommonJs modular format
  • Check whether AMD (define) is supported or not. If the define exists, load it in AMD mode
  • Define (Factory) is a global function used to define modules in either AMD or CMD environments
  • If neither exists, then hang the module globally (window or global).

1. Basic grammar

( function(name, Var hasExports = typeof Module define === 'function' var hasExports = typeof Module! = 'undefined' && module.exports if(hasDefine) { define(factory) }else if(hasExports) { module.exports = factory() }else{  this[name] = factory() } } )('xxx',function(){})Copy the code

7.ES6 Module

With ES6, instead of modularizing with closures and functions, you need an escape tool like Babel to compile,

The idea is to try to be as static as possible, you can determine these things at compile time, whereas CommonJS and AMD can only determine these things at runtime

1. Basic grammar

// modulea.js var a = 'a' export {a: a} import {a} from './ modulea.js'Copy the code
  • ES6 uses file-based modules, which must be one file at a time. Multiple modules cannot be combined into a single file
  • The ES6 module API is static, and once the module is imported, you cannot add methods to your program
  • ES6 uses reference bindings (Pointers), which are different from CommonJS values. If your module changes the value of an exported variable during runtime, it will be reflected in the code that uses the module
  • ES6 modules use singleton mode, each import of the same module actually points to the same instance