11
头图

JavaScript-模块 _1_.png

The meaning of modularity

Split the code into independent blocks, and then connect these blocks using the module pattern to achieve different functions.

Just like the puzzles played in childhood, different puzzles can be combined into any shape.

The idea behind this model is also very simple: divides the logic into blocks and encapsulates them independently, and at the same time decides to introduce and execute those external modules and those modules that expose themselves.

This basic idea is the foundation of all JavaScript module systems.

The code case address in the article: https://github.com/AnsonZnl/JS-Modules-Sample

The benefits of modularity

  • Avoid naming conflicts (reduce namespace pollution)
  • Better separation, on-demand loading
  • Higher reusability
  • High maintainability

Common modules in JS

IIFE mode: anonymous function self-calling (closure)

The main application is on the browser side.

Use the principle of closure to create a unique function scope to store private variables, achieving a modular effect.

uses

HTML

<script type="text/javascript" src="module.js"></script>
<script type="text/javascript">
  console.log(myModule.get()); // output-data(获取内部数据)
  myModule.set("new data"); // 设置内部数据
  console.log(myModule.data); //output-undefined (不能访问模块内部数据)
  myModule.data = "xxxx"; //不是修改的模块内部的data
  console.log(myModule.get()); //output-new data 修改后的值
</script>

JS

// module.js文件
(function(window) {
  let data = "data";
  //获取数据
  function get() {
    return data;
  }
  // 修改数据
  function set(val) {
    data = val;
  }
  //暴露行为
  window.myModule = {
    get,
    set,
  };
})(window);

CommonJS

The main application is on the server side. If running on the browser side, other tools (Browserify) are needed.

exposed module: module.exports = value or exports.xx = value (exports is an exported object)

introduces the module: require(xx) , if it is a third-party module, xxx is the module name, if it is a custom module, xxx is the file path of the module.

features

  • All code runs in the module scope and will not pollute the global scope.
  • The module can be loaded multiple times, but it will only run once when it is loaded for the first time, and then the running result is cached, and when it is loaded later, the cached result is directly read. To make the module run again, the cache must be cleared.
  • The order in which the modules are loaded is in the order in which they appear in the code.

uses
Install uniq functions in Node.

npm init
npm install uniq --save
// module.js
let arr = [1, 2, 2, 3, 3];
module.exports = {
  arr,
};
// app.js
let module1 = require("./module.js");
let uniq = require("uniq");

console.log(uniq(module1.arr)); // [1,2,3]

AMD

The full name is Asynchronous Module Definition-Asynchronous Module Definition

Unlike CommonJS, AMD uses an asynchronous method to load modules.

basic syntax

Define the exposed module

// 定义没有依赖的模块
define(function() {
  return 模块;
});
// 定义有依赖的模块
define(["module1", "module2"], function(m1, m2) {
  return 模块;
});

Introduce and use modules

require(["module1", "module2"], function(m1, m2) {
  使用m1 和 m2;
});

use case

<!-- index.html -->
<body>
  <!-- 引入require.js并指定js主文件的入口 -->
  <script
    data-main="main"
    src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
  ></script>
</body>
// main.js
(function() {
  require(["module.js"], function(module) {
    let currentUrl = module.getUrl();
    alert("当前页面的URl:" + currentUrl);
  });
})();
// module.js
// 定义模块
define(function() {
  let url = window.location.href;

  function getUrl() {
    return url.toUpperCase();
  }
  // 暴露模块
  return {
    getUrl,
  };
});

For more usage methods, please refer to: https://requirejs.org/

CMD

CMD--- is the standardized output of SeaJS's module definition in the promotion process. It is a synchronous module definition. It is a standard of SeaJS. SeaJS is an implementation of the CMD concept. SeaJS is a JS framework for module development provided by the Taobao team. .

When it is used and when it is introduced, it is returned when it is used. This is a synchronization concept.

features: CMD is a specification improved on the basis of AMD. The difference from AMD is that the execution mechanism of dependent modules is different. CMD is dependent on the nearest, and AMD is dependent on the front.

environment: browser environment

syntax:

  • Import: define(function(require, exports, module){})
  • Export: define(function(){return'value'})

use

// main.js
define(function(require, exports, module) {
  var moduleA = require("./module.js");
  alert(moduleA.a); // 打印出:hello world
});
// module.js
define(function(require, exports, module) {
  exports.a = "hello world";
});
<body>
  <script
    data-main="main"
    src="https://cdn.bootcdn.net/ajax/libs/require.js/2.3.6/require.js"
  ></script>
</body>

For Sea.js usage, please refer to: https://seajs.github.io/seajs/docs/

UMD

The full name of Universal Module Definition is known by the name. It is characterized by compatibility with AMD and CommonJS specifications, and compatibility with global introduction.

environment: server environment and browser side

implementation principle of 160b06148ae0fc UMD is very simple:

  • First judge whether AMD is supported (whether define exists), and if it exists, use AMD to load the module;
  • Then judge whether it supports the Node.js module format (whether exports exist), and if it exists, use the Node.js module format;
  • If the first two do not exist, the module will be exposed to the global (window or global)

uses

(function(root, factory) {
  if (typeof define === "function" && define.amd) {
    //AMD
    define(["jquery"], factory);
  } else if (typeof exports === "object") {
    //Node, CommonJS之类的
    module.exports = factory(require("jquery"));
  } else {
    //浏览器全局变量(root 即 window)
    root.returnExports = factory(root.jQuery);
  }
})(this, function($) {
  //方法
  function myFuncA() {} // 私有方法,因为没有返回
  function myFuncB() {} // 公共方法,因为返回了

  //暴露公共方法
  return {
    myFuncB,
  };
});

The CND of jQuery that you usually introduce is UMD. The source code can be viewed: https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js

ES6 Module

Before ES6, modularization was mainly promoted by the community, and there were two CommonJS and AMD. The former was used for servers and the other was used for browsers. The emergence of ES6 modules would completely replace CommonJS and AMD specifications and become browsers and A universal solution for servers.

The design idea of ES6 modules is to be as static as possible, so that the dependencies of the modules and the input and output variables can be determined at compile time. Both CommonJS and AMD modules can only determine these things at runtime. For example, CommonJS modules are objects, and object attributes must be searched when typing.

Features :

  • Load on demand (load at compile time)
  • The import and export commands can only be at the top level of the module, not in the code block (for example: in the if statement), the import() statement can be dynamically loaded in the code block to achieve asynchronous dynamic on-demand dynamic loading

environment: server environment and browser side

syntax:

  • Import: import {modules1,modules1,} from'module path'
  • Export: export or export default
  • Dynamic import: import('module path').then(..)
    <!-- tree-shaking -->

uses

Install Babel in Node first:

npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
npm install --save @babel/polyfill
# 然后运行
npx babel-node main.js
// modules/double.js
let mes = "Hello Modules for double";
function sum(value) {
  return `${mes} - ${value * 2}`;
}
export default {
  mes,
  sum,
};
// main.js
import module from "./modules/double";
console.log(module.sum(10)); // Hello Modules for double - 20

In the browser

difference

  • The difference with CommonJS:

    • The output of the CommonJS module is a value worth copying, and the output of the ES6 module is a reference to the value
    • The CommonJS module is loaded at runtime, and the ES6 module is the output interface at compile time
    • The require() of the CommonJS module is to load the module synchronously, and the import command of the ES6 module is to be loaded asynchronously, and there is an independent module dependency analysis stage.

Disadvantages
The current support of the browser and server is not very good. At this stage, some tools are needed ( Babel ).

  • <script type="module" src="./foo.js"></script> can be used in the new version of the browser (such as Chrome)
  • Server support (Node) has two modes, namely ES6 module and CommonJS.

    • Starting Node.js v13.2, the default support ES6 module, but need .mjs name suffix, or in package.json modification type field module (recommended)
    • If you use CommonJS, you need to use .cjs as the suffix. You can also set the type field in package.json to modify the commonjs (recommended).

It is best not to mix the two. For more usage methods, please refer to: https://es6.ruanyifeng.com/#docs/module

to sum up

  • The CommonJS specification is mainly used for server-side programming, and the loading module is synchronous, which is not suitable for the browser environment, because synchronization means blocking loading, and browser resources are loaded asynchronously, so there is the AMD CMD solution.
  • The AMD specification loads modules asynchronously in the browser environment, and multiple modules can be loaded in parallel. However, AMD specification development costs are high, code reading and writing are difficult, and the semantics of the module definition method is not smooth.
  • The CMD specification is very similar to the AMD specification. Both are used for browser programming, relying on the nearest, delayed execution, and can be easily run in Node.js. However, relying on SPM packaging, the loading logic of the module is biased
  • ES6 implements the module function at the level of language standards, and the implementation is quite simple, it can completely replace CommonJS and AMD specifications, and become a common module solution for browsers and servers.

reference

original article

九旬
1.1k 声望1.2k 粉丝